この章では、Oracle DatabaseでのSQL文の処理方法について、アプリケーション開発者が知っておく必要がある内容について説明します。この章を読む前に、『Oracle Database概要』でSQL文およびSQL処理の基本情報を確認してください。
内容は次のとおりです。
ここでは、SQL文の実行時に処理の各ステージで何が行われるかを、例としてデータ操作言語(DML)文を使用して説明します。
ある部門の全従業員の昇給を行うためにPro*Cプログラムを使用しているとします。プログラムはOracle Databaseに接続しており、操作を行うユーザーはemployees
表を所有するHRスキーマに接続しています。プログラムには次のSQL文を埋め込むことができます。
EXEC SQL UPDATE employees SET salary = 1.10 * salary WHERE department_id = :department_id;
プログラムでは、SQL文の実行時に使用するバインド変数プレースホルダ:department_id
の値が提供されます。
内容は次のとおりです。
カーソルをオープンまたは作成します。
プログラム・インタフェース・コールにより、SQL文を予想して、カーソルがオープンまたは作成されます。ほとんどのアプリケーションではカーソルの作成は暗黙的(自動的)に行われます。プリコンパイラ・プログラムでは、カーソルを暗黙的または明示的に作成します。
文を解析します。
SQL文がユーザー・プロセスからOracle Databaseに渡され、文の解析済表現が共有SQL領域にロードされます。Oracle Databaseは、解析中に多くのエラーを捕捉できます。
文が問合せかどうかを判別します。
文が問合せの場合、結果を記述します。
注意: このステージが必要になるのは、結果の性質が不明な場合のみです。たとえば、ユーザーが対話的に問合せを入力する場合などです。 |
Oracle Databaseによって結果の性質(データ型、長さおよび名前)が決まります。
文が問合せの場合、出力を定義します。
フェッチされる各値を受け取るために定義する変数の場所、サイズおよびデータ型を指定します。このような変数は定義変数と呼ばれます。必要な場合にはOracle Databaseによってデータ型の変換が行われます。
参照: DEFINE ステージの詳細は、『Oracle Database概要』を参照してください。 |
変数がある場合はバインドします。
Oracle DatabaseはSQL文の意味を判別していますが、文を実行するために十分な情報は得ていません。Oracle Databaseでは、文に指定されているすべてのバインド変数プレースホルダの値が必要です。例では、:department_id
の値が必要です。これらの値を獲得するプロセスは変数のバインドと呼ばれます。
値の場所(メモリー・アドレス)をプログラムで指定する必要があります。アプリケーションのエンドユーザーは、Oracle Databaseユーティリティから値の入力を求められることがあるため、バインド変数プレースホルダの値を指定していると認識していない場合もあります。
値の場所(つまり参照によるバインド)がプログラムによって指定されるため、値が変更された場合でも、文の再実行の前に変数を再バインドする必要はありません。Oracle Databaseは文の実行のたびにそのアドレスから変数の値を取得します。
Oracle Databaseでデータ型変換を実行する必要がある場合は、デフォルトでまたは暗黙的に指定する場合を除き、各値のデータ型と長さも指定する必要があります。
参照: 値のデータ型と長さの指定の詳細は、次の資料を参照してください。
|
(オプション)文をパラレル化します。
Oracle Databaseでは、問合せと一部のデータ定義言語(DDL)操作(索引作成、副問合せによる表作成、パーティションに対する操作など)をパラレル化することができます。パラレル化では、処理が早く完了するように、複数のサーバー・プロセスでSQL文の処理を実行します。
文を実行します。
Oracle Databaseは文を実行します。文が問合せまたはINSERT
文の場合、データは変更されないためデータベースは行をロックする必要はありません。ただし、文がUPDATE
文またはDELETE
文の場合は、それにより影響を受けるすべての行を、そのトランザクションの次のCOMMIT
、ROLLBACK
またはSAVEPOINT
まで、データベースがロックします。これによりデータの整合性が確保されます。
一部の文では実行が複数回行われるように指定できます。これは配列処理と呼ばれます。実行回数をnと指定すると、バインドおよび定義の場所が、サイズnの配列の先頭であるとみなされます。
文が問合せの場合、行をフェッチします。
Oracle Databaseは行を選択し、問合せにORDER
BY
句が含まれる場合は、行の順序付けを行います。後続の各フェッチにより結果セットの行が1行ずつ取得され、最後の行がフェッチされるまで続きます。
カーソルをクローズします。
Oracle Databaseはカーソルをクローズします。
注意: トランザクション管理、セッション管理またはシステム管理SQL文を再実行するには、別のEXECUTE 文を使用します。 |
Oracle Databaseは、アプリケーションが類似したSQL文をデータベースに送信すると自動的に検出します。その文の最初の処理時に使用されたSQL領域が共有されます。つまり、後で出現する同じ文の処理に使用されます。このため、一意の文に対して存在する共有SQL領域は1つのみです。共有SQL領域は共有メモリー領域であるため、すべてのOracle Databaseプロセスが共有SQL領域を使用できます。SQL領域の共有により、データベース・サーバーでのメモリー使用量が減るため、システム・スループットが向上します。
Oracle Databaseでは、文が類似しているか同一かを決定する際に、ユーザーやアプリケーションによって直接発行されたSQL文と、DDL文によって内部的に発行された再帰的SQL文の両方が比較されます。
参照:
|
内容は次のとおりです。
参照: トランザクションの基本情報は、『Oracle Database概要』を参照してください。 |
一般に、トランザクションへの操作のグループ化方法の決定は、Oracle Databaseのプログラム・インタフェースを使用するアプリケーション開発者が考慮します。トランザクションのグループ化方法を決定する際は、次の規則に従います。
論理単位ごとに作業が完成し、データの一貫性が保たれるように、トランザクションを定義します。
すべての参照表の中のデータは、トランザクションが開始する前および終了した後で、一貫した状態であることを確認します。
各トランザクションは、データに対する一貫した変更を1つ含むSQL文またはPL/SQLブロックのみで構成されていることを確認します。
たとえば、口座間で預金を移動できるWebアプリケーションを作成すると仮定します。このトランザクションには、一方の口座の借方への記帳(1つのSQL文で実行)ともう一方の口座の貸方への記帳(もう1つのSQL文で実行)が含まれる必要があります。2つの文で1つの作業単位となり、両方が成立するか両方が不成立かのいずれかである必要があります。つまり、片方の文はもう片方のコミットなしでコミットすることはできません。一方の口座への預金など、関連のないアクションは、同じトランザクションに含めないでください。
アプリケーション開発者は、パフォーマンスの改善を試みる必要があります。アプリケーションの設計および作成では、次のパフォーマンス改善のテクニックを使用することを検討してください。
各トランザクションに対して、次を行います。
単一のSQL文を使用できる場合、それを使用します。
単一のSQL文を使用できないが、PL/SQLを使用できる場合、できるだけ小さいPL/SQLを使用します。
PL/SQLの詳細は、第II部「アプリケーション開発者用のPL/SQL」を参照してください。
(ディレクトリの読取りなど、実行する必要のあることができないため) PL/SQLを使用できない場合、Javaを使用します。
Javaを使用できない場合(非常に低速な場合など)、または既存の第三世代言語(3GL)コードがある場合、外部Cサブプログラムを使用します。
アプリケーションでのJavaおよびCの使用方法の詳細は、第18章「複数のプログラミング言語を使用したアプリケーションの開発」を参照してください。
共有SQL領域を利用できるように、SQL文の発行基準を確立します。
Oracle Databaseが同一のSQL文を認識し、SQL文がメモリー領域を共有できるようにします。これによって、データベース・サーバー上のメモリー使用量が減少し、システム・スループットが向上します。
統計を収集します。Oracle Databaseは統計を使用して、SQL文を最適化するコストベースの方法を実装することができます。必要に応じて、オプティマイザへの追加のヒントを使用できます。
ほとんどの統計の収集にはDBMS_STATS
パッケージを使用します。このパッケージでは、パラレルでの統計の収集、パーティション化されたオブジェクトのグローバル統計の収集、その他の方法での統計収集のチューニングを行うことができます。このパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。
コストベースのオプティマイザに関係しない統計収集(空きリスト・ブロックに関する情報収集など)では、SQL文ANALYZE
を使用します。この文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
ヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
トランザクションを開始する前にDBMS_APPLICATION_INFO.SET_ACTION
プロシージャを起動し、トランザクションの名前をデータベースに登録し、後でOracle TraceおよびSQLトレース機能を使用してパフォーマンスをトラッキングするときに使用できるようにします。DBMS_APPLICATION_INFO
パッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。
ユーザーが作成したPL/SQLファンクションをSQL式に組み込んで、ユーザーの生産性および問合せ効率を向上させます。詳細は、11.9項「SQL文からのストアドPL/SQLファンクションの起動」を参照してください。
参照: トランザクション管理の詳細は、『Oracle Database概要』を参照してください。 |
トランザクションがOracle Databaseを更新するとき、これに対応するREDOエントリが生成されます。このREDOエントリは、トランザクションが完了するまで、Oracle DatabaseによりREDOログにバッファリングされます。トランザクションがコミットされると、それに応じてログ・ライター・プロセス(LGWR)により、トランザクション内のすべての変更のバッファリングされたREDOエントリに対し、REDOレコードがディスクに書き込まれます。デフォルトでは、REDOエントリは、コールがクライアントに戻される前に、Oracle Databaseによりディスクに書き込まれます。この動作のためにアプリケーションはREDOエントリがディスクに永続的に書き込まれるのを待機する必要があり、コミットに待機時間が発生します。
Oracle Databaseでは、アプリケーションのニーズに応じてコミットREDOの処理を変更できます。アプリケーションで非常に高いトランザクション・スループットが必要とされるため、コミットでの待機時間を短くするためにコミットの永続性を放棄してもよい場合は、デフォルトのCOMMIT
オプションを変更して、データベースでデータがオンラインREDOログへ書き込まれるのをアプリケーションが待機しなくて済むようにできます。
表6-1はCOMMIT
オプションの一覧です。
注意: NOWAIT オプションを指定した場合、コミット・メッセージの受信後、REDOログ・レコードへの書込み前に障害が発生すると、トランザクションにその変更が永続的であると誤って示す可能性があります。 |
表6-1 COMMIT文のオプション
COMMIT
オプションを変更するには、COMMIT
文(『Oracle Database SQL言語リファレンス』を参照)、または適切な初期化パラメータを使用します。初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。
注意: 分散トランザクションの場合、デフォルトのIMMEDIATE およびWAIT アクションは変更できません。 |
Oracle Call Interface(OCI)を使用するアプリケーションの場合、アプリケーション内でOCITransCommit
ファンクションに次のフラグを設定することにより、REDO動作を変更できます。
OCI_TRANS_WRITEWAIT
OCI_TRANS_WRITENOWAIT
OCI_TRANS_WRITEBATCH
OCI_TRANS_WRITEIMMED
注意: OCI_TRANS_WRITENOWAIT の使用時には、トランザクションが強制終了、強制起動、インスタンス障害またはノード障害で警告なしに消失する可能性があります。Oracle RACシステムでは非同期にコミットした変更は、他のインスタンスですぐに読み込めない場合があります。 |
参照: OCITransCommit ファンクションの詳細は『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。 |
NOWAIT
およびBATCH
オプションの指定では、問題が発生しやすい期間が短くなります(このような期間には、アプリケーションがコミット済として認識するトランザクションをOracle Databaseがロールバックできます)。アプリケーションは、次のような状況に対応できる必要があります。
データベース・ホストの障害。バッファには格納されていても、まだオンラインREDOログに書き込まれていないREDOエントリが失われる可能性があります。
ファイルI/Oの問題で、LGWRによるバッファ済REDOエントリのディスクへの書込みが妨げられる場合。REDOログが多重化されていない場合、コミットが失われます。
リカバリ可能な停止は、アプリケーション(クライアント)とOracle Database (サーバー)間の接続を切断する、システム、ハードウェア、通信または記憶域の障害です。停止後、アプリケーションには切断に関するエラー・メッセージが表示されます。接続が切断されたときに実行されていたトランザクションは、進行中のトランザクションで、完了までコミットまたは実行された、またはされていない可能性があります。
停止からリカバリするには、アプリケーションが進行中のトランザクションの結果(コミットされたかどうか、およびセッションの状態が意図どおりに変更されたかどうか)を確認する必要があります。トランザクションがコミットされていなかった場合、アプリケーションはトランザクションを再発行するか、エンドユーザーに未コミット・ステータスを戻すことができます。トランザクションがコミットされていた場合、アプリケーションは切断エラーではなくコミット済ステータスをエンドユーザーに戻すことができます。トランザクションがコミットされていると同時に完了している場合、アプリケーションは新規セッションを使用してセッションの状態を再確立することによって処理を続行できる可能性があります。
進行中のトランザクションの結果をアプリケーションに提供し、トランザクションが重複していないことを確認するために使用できるOracle Database機能は、トランザクション・ガードで、そのApplication Program Interface (API)はPL/SQLプロシージャDBMS_APP_CONT.GET_LTXID_OUTCOME
です。
内容は次のとおりです。
トランザクション・ガードは、停止後に進行中のトランザクションの結果をアプリケーションに提供するために使用できるOracle Databaseツールです。アプリケーションはトランザクション・ガードを使用して、停止後に既知の結果を(コミット済または未コミット)をエンドユーザーに提供できるとともに、必要に応じて、トランザクションがコミットされておらず状態が正しい場合はトランザクションをリプレイすることもできます。
トランザクション・ガードは、6.2.4.2項で説明するように、API、PL/SQLプロシージャDBMS_APP_CONT.GET_LTXID_OUTCOME
を介してトランザクション結果を提供します。
トランザクション・ガードは、失敗したセッション上の最後の進行中のトランザクションを識別するグローバル一意識別子である論理トランザクション識別子(LTXID)に依存します。データベースは、トランザクションがコミットされるとLTXIDを記録し、コミット・メッセージとともに新規LTXIDをクライアントに(クライアントのラウンド・トリップごとに)戻します。クライアント・ドライバは、次回のCOMMIT
時に使用するLTXIDを常に保持します。
注意:
|
トランザクション・ガードは、LTXIDを次のように使用します。
トランザクションの実行中、Oracle Database (サーバー)とアプリケーション(クライアント)の両方が次回のCOMMIT
時に使用するLTXIDを保持します。
トランザクションがコミットされると、Oracle DatabaseはトランザクションとともにLTXIDを記録します。LTXIDがすでにコミットされているかブロックされている場合、データベースはエラーを発生させ、トランザクションの重複を阻止します。
LTXIDは、RETENTION_TIMEOUT
パラメータによって指定されている時間にわたってOracle Database内に存在し続けます。デフォルトは24時間です。この値を変更する手順は、次のとおりです。
Real Application Clustersを実行している場合、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』で説明されている、サーバー制御ユーティリティ(SRVCTL)を使用します。
Real Application Clustersを使用していない場合、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』で説明されている、DBMS_SERVICE
パッケージを使用します。
トランザクションがリモートであるか分散されている場合、LTXIDはローカル・データベース内に永続化されます。
LTXIDは標準REDO適用時にData GuardおよびActive Data Guardに転送されます。
リカバリ可能なエラーの後:
トランザクションがコミットされていない場合、Oracle DatabaseはLTXIDをブロックすることにより、同じLTXIDを持つ以前の進行中のトランザクションをコミットできないようにします。
この動作により、アプリケーションは未コミット結果をユーザーに戻すことができ、ユーザーは実行内容を決定できるようになります。また、アプリケーションは必要に応じて、アプリケーションを安全にリプレイすることもできます。
トランザクションがコミットされている場合、アプリケーションはこの結果をエンドユーザーに戻すことができ、状態が正しい場合、アプリケーションは継続できます。
トランザクションがロールバックされる場合、Oracle DatabaseはLTXIDを再利用します。
参照:
|
PL/SQLプロシージャDBMS_APP_CONT.GET_LTXID_OUTCOME
は、トランザクション・ガードのAPIです。停止後、アプリケーションはOracle Databaseに再接続してから、このプロシージャを呼び出して進行中のトランザクションの結果を確認できます。
DBMS_APP_CONT.GET_LTXID_OUTCOME
には、次のパラメータがあります。
パラメータ名 | データ型 | パラメータ・モード | 値 |
---|---|---|---|
CLIENT_LTXID |
RAW |
IN |
進行中のトランザクションのLTXID |
COMMITTED |
BOOLEAN |
OUT |
進行中のトランザクションがコミットされた場合はTRUE 、そうでない場合はFALSE |
USER_CALL_COMPLETED |
BOOLEAN |
OUT |
進行中のトランザクションが完了した場合はTRUE 、そうでない場合はFALSE |
内容は次のとおりです。
参照: DBMS_APP_CONT.GET_LTXID_OUTCOME の詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください |
アプリケーション(クライアント)が進行中のトランザクションのLTXIDを使用してDBMS_APP_CONT.GET_LTXID_OUTCOME
を呼び出すには、クライアント・ドライバを使用してクライアント・ドライバで使用中の最後のLTXIDを取得する必要があります。クライアント・ドライバは、次回コミットするトランザクションのLTXIDを保持します。この場合、このLTXIDは停止時に進行中のトランザクション用です。JDBC-ThinドライバにはgetLTXID
、ODP.NETにはLogicalTransactionId
、OCIおよびOCCIにはLTXIDとともにOCI_ATTR_GET
を使用します。
JDBC-Thinドライバには、クライアント・ドライバのLTXIDが変更されるたびにトリガーされるコールバックも用意されています。このコールバックを使用して、使用対象の現在のLTXIDを保持できます。このコールバックは、実行の繰返しをブロックする必要があるアプリケーション・サーバーおよびアプリケーションに対して特に役立ちます。
注意: アプリケーションは、LTXIDをDBMS_APP_CONT.GET_LTXID_OUTCOME に渡す直前にこれを取得する必要があります。LTXIDを事前に取得すると、以前のLTXIDがDBMS_APP_CONT.GET_LTXID_OUTCOME に渡される可能性があり、この場合、リクエストが拒否されます。 |
クライアント・ドライバの詳細は、クライアント・ドライバの関連ドキュメントを参照してください。次に例を示します。
JDBCタイプ2およびタイプ4ドライバの場合、『Oracle Database JDBC開発者ガイド』を参照してください。
OCIドライバ(OCCIを含む)の場合、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。
ODP.NETドライバの場合は、『Oracle Data Provider for .NET開発者ガイドfor Microsoft Windows』を参照してください。
DBMS_APP_CONT.GET_LTXID_OUTCOME
からアプリケーションに制御が戻された後、アプリケーションは、仮パラメータCOMMITTED
に対応する実際のパラメータの値を確認することにより、進行中のトランザクションがコミットされたかどうかを確認できます。
実際のパラメータの値がTRUE
である場合、トランザクションはコミットされています。
実際のパラメータの値がFALSE
である場合、トランザクションはコミットされていません。このため、アプリケーションがコードUNCOMMITTED
をエンドユーザーに戻したり、これを使用してトランザクションをリプレイしても安全です。
アプリケーションがUNCOMMITTED
を戻した後に以前のセッションがトランザクションをコミットしないようにするために、DBMS_APP_CONT.GET_LTXID_OUTCOME
によってLTXIDがブロックされます。LTXIDをブロックすることにより、エンドユーザーが未コミット状態に基づいて決定を下したり、アプリケーションがトランザクションをリプレイできるようになり、トランザクションの重複が阻止されます。
一部のトランザクションは完了時に情報を戻します。たとえば、成功時にコミット(自動コミット)を使用するトランザクションは、影響を受ける行の数、またはSELECT
文の場合は行自体を戻すことができます。OUT
パラメータを持つPL/SQLサブプログラムを呼び出すトランザクションは、これらのパラメータの値を戻します。PL/SQLファンクションを呼び出すトランザクションは、ファンクション値を戻します。また、PL/SQLサブプログラムを呼び出すトランザクションは、COMMIT
文を実行してからこれ以外の処理を行うことができます。
進行中のトランザクションが完了時に戻す情報、またはデータベースの変更のコミット後にトランザクションが行うセッション状態の変更をアプリケーションが必要とする場合、アプリケーションは、進行中のトランザクションが完了したかどうかを確認する必要があります。これを行うには、仮パラメータUSER_CALL_COMPLETED
に対応する実際のパラメータの値を確認します。
実際のパラメータの値がTRUE
である場合、トランザクションは完了しており、アプリケーションには続行する必要がある情報および処理が存在します。
実際のパラメータの値がFALSE
である場合、クライアントからのコールは完了していない可能性があります。このため、アプリケーションには続行する必要がある情報および処理が存在しない可能性があります。
アプリケーション(クライアント)とOracle Database (サーバー)が同期していない場合、DBMS_APP_CONT.GET_LTXID_OUTCOME
プロシージャにより、次のいずれかの例外が発生します。
例外 | 説明 |
---|---|
ORA-14950: SERVER_AHEAD |
サーバーがクライアントより進んでいます。つまり、アプリケーションがDBMS_APP_CONT.GET_LTXID_OUTCOME に渡したLTXIDにより、進行中のトランザクションより古いトランザクションが識別されます。
アプリケーションは、LTXIDを |
ORA-14951 - CLIENT_AHEAD |
クライアントがサーバーより進んでいます。サーバーが、以前の状態にフラッシュバックされたか(第16章「Oracle Flashback Technologyの使用」を参照)、メディア・リカバリを使用してリカバリされたか、以前にオープンされたスタンバイ・データベースであり、データが紛失しました(メディア・リカバリおよびスタンバイ・データベースの詳細は、『Oracle Data Guard概要および管理』を参照)。 |
ORA-14906 - SAME_SESSION |
LTXIDを所有するセッションでのGET_LTXID_OUTCOME の実行はサポートされていません。これは、この実行によってこのセッションに対する追加処理がブロックされるためです。 |
ORA-14909 - COMMIT_BLOCKED |
同じユーザー名を持つ別のユーザーによってGET_LTXID_OUTCOME を使用してセッションのコミットがブロックされています。GET_LTXID_OUTCOME はデッド・セッションに対してのみ呼び出す必要があります。ライブ・セッションのブロックは、ALTER SYSTEM KILL SESSION IMMEDIATE を使用した方が確実に実行できます。不明な点は、アプリケーション管理者に問い合せてください。 |
ORA-14952 GENERAL ERROR |
DBMS_APP_CONT.GET_LTXID_OUTCOME では、進行中のトランザクションの結果を確認できません。トランザクションの処理中にエラーが発生し、エラー・スタックにエラー詳細が表示されます。 |
アプリケーション(クライアント)は、エラー・メッセージを受け取った後、次の手順を実行してトランザクション・ガードを使用する必要があります。
エラーの原因が停止(リカバリ可能)であるかどうかを確認します。
手順については、クライアント・ドライバの関連ドキュメントを参照してください(OCI、OCCIおよびODP.NETはOCI_ATTRIBUTE
、JDBCはisRecoverable
)。
エラーがリカバリ可能である場合、クライアント・ドライバのAPIを使用して、進行中のトランザクションの論理トランザクション識別子(LTXID)を取得します。
手順については、クライアント・ドライバの関連ドキュメントを参照してください。
データベースを再接続します。
アプリケーションが取得するセッションには、新規セッションまたはプール・セッションがあります。
手順2のLTXIDを使用してDBMS_APP_CONT.GET_LTXID_OUTCOME
を呼び出します。
仮パラメータCOMMITTED
に対応する実際のパラメータの値を確認します。
値がTRUE
である場合、進行中のトランザクションがコミットされたことをアプリケーションに伝えます。アプリケーションはこの結果をエンドユーザーに戻すことができ、状態が正しい場合、アプリケーションは継続できます。
値がFALSE
である場合、アプリケーションはUNCOMMITTED
または同様のメッセージをユーザーに戻すことができ、ユーザーは次の手順を選択できるようになります。オプションとして、アプリケーションはユーザーに対してトランザクションをリプレイできます。次に例を示します。
必要な場合、クライアント側で状態の変更をクリーン・アップします。
進行中のトランザクションを再発行します。
進行中のトランザクションを再発行しないときに、進行中のトランザクションが完了時に戻す情報や、データベースの変更のコミット後にトランザクションが実行する処理をアプリケーションが必要としない場合は、続行します。それ以外の場合、仮パラメータUSER_CALL_COMPLETED
に対応する実際のパラメータの値を確認します。
値がTRUE
である場合、続行します。
値がFALSE
である場合、アプリケーションを続行できないことをアプリケーション・ユーザーに伝えます。
デフォルトでは、Oracle Databaseでは、文レベルの読取り一貫性は保証されますが、トランザクション・レベルの読取り一貫性は保証されません。文レベルの読取り一貫性を持つ場合、ある文に含まれる問合せは、この文の存続中、一貫性のあるデータを生成します。その他の文による変更は反映されません。トランザクション・レベルの読取り一貫性(反復可能読取り)を持つ場合、あるトランザクションに含まれる問合せは、このトランザクションの存続中、一貫性のあるデータを生成します。その他のトランザクションによる変更は反映されません。
DML文を含まないトランザクションに対するトランザクション・レベルの読取り一貫性を保証するには、このトランザクションを読取り専用に指定します。読取り専用トランザクションに含まれる問合せには、このトランザクションが開始される前にコミットされた編集以外見えないため、トランザクションの存続中、問合せの結果の一貫性が保たれます。
読取り専用トランザクションは、データ・ロックを追加取得することなしに、トランザクション・レベルの読取り一貫性を提供します。したがって、読取り専用トランザクションがデータを問い合せている間、別のトランザクションが同じデータを問い合せ、更新することができます。
SET TRANSACTION READ ONLY [ NAME string ];
SET
TRANSACTION
READ
ONLY
文の前に来ることができるのは、DDL文のみです。SET
TRANSACTION
READ
ONLY
文の実行が正常に終了した後で、このトランザクションはSELECT
(ただし、FOR
UPDATE
なしで)、COMMIT
、ROLLBACK
、または非DML文(SET
ROLE
、ALTER
SYSTEM
、LOCK
TABLE
など)のみを含むことができます。COMMIT
、ROLLBACK
、またはDDL文は読取り専用トランザクションで終わります。
参照: SET TRANSACTION 文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
実行時間の長い問合せでは、読取り一貫性(CR)操作に必要なUNDO情報が無効になったためにエラーが発生することがあります。これは、アクティブなトランザクションによって、コミット済UNDOブロックが上書きされた場合に起こります。
自動UNDO管理を行うと、データベース管理者(DBA)は、パラメータUNDO_RETENTION
を使用してUNDO情報のデータベースでの保存期間を明示的に制御できます。たとえば、UNDO_RETENTION
が30分である場合、すべてのコミット済UNDO情報は、最低30分間データベースに保持されます。この設定により、実行時間が30分以内の問合せでOERエラー「スナップショットが古すぎます。」が発生することはなくなります。
参照:
|
Oracle Databaseには、データの同時実行性、データの整合性、および文レベルでの読取り一貫性を保持するための、デフォルト・ロック・メカニズムが用意されています(これらの詳細は、『Oracle Database概要』を参照)。ただし、これらのメカニズムは表を明示的にロックすることによりオーバーライドできます。表の明示的なロックは次のような状況で役立ちます。
アプリケーション内のあるトランザクションが他のトランザクションの完了を待機する必要がなくなるように、リソースに対して排他的にアクセスするトランザクションが必要な場合。
アプリケーションで、トランザクション・レベルの読取り一貫性(反復可能読取り)が必要な場合。
トランザクション・レベルの読取り一貫性を保証する他の方法については、6.3項「読取り専用トランザクションでの反復可能読取りの保証」、および6.6項「シリアライズ可能トランザクションを使用した同時実行性の制御」を参照してください。
次のどのSQL文を使用しても、デフォルト・ロックをトランザクション・レベルでオーバーライドできます。
LOCK
TABLE
(『Oracle Database SQL言語リファレンス』を参照)
FOR
UPDATE
句付きSELECT
文(『Oracle Database SQL言語リファレンス』を参照)
READ
ONLY
またはISOLATION
LEVEL
SERIALIZABLE
オプションを指定したSET
TRANSACTION
(『Oracle Database SQL言語リファレンス』を参照)
これらの文によって取得されるロックは、トランザクションのコミット後またはロールバック後に解除されます。
参照:
|
DMLロックの最大数は、DML_LOCKS
初期化パラメータ(『Oracle Databaseリファレンス』を参照)によって決定されます。通常、デフォルト値には十分な値が設定されていますが、明示的なロックを使用する際に、この値を大きくする必要がある場合があります。
注意: いずれかのレベルでOracle Databaseのデフォルト・ロックをオーバーライドする場合は、データ整合性が保証されていること、データ同時実行性が許容されていること、およびデッドロックの可能性がないか、デッドロックが適切に処理されていることを確認してください。 |
内容は次のとおりです。
自らのスキーマの表に対して表のロックを取得するためには、特別な権限は必要ありません。他スキーマ内の表に対して表ロックを取得するには、LOCK
ANY
TABLE
システム権限またはその表に対する(SELECT
やUPDATE
などの)オブジェクト権限が必要です。
LOCK
TABLE
文が実行されると、トランザクションは指定された表ロックを明示的に取得します。LOCK
TABLE
文は、デフォルト・ロックを明示的にオーバーライドします。ビューに対してLOCK
TABLE
文が発行されると、基礎となる実表がロックされます。次の文は、その文が含まれるトランザクションのために、employees
表およびdepartments
表に対する排他表ロックを取得します。
LOCK TABLE employees, departments IN EXCLUSIVE MODE NOWAIT;
ロック・モードが同じ場合は、ロックする表またはビューを複数指定できます。ただし、各LOCK
TABLE
文に指定できるロック・モードは1つのみです。
LOCK
TABLE
文では、表ロックの待ち時間も指示できます。
ロックを待機しない場合は、NOWAIT
またはWAIT 0
を指定します。
表ロックがすぐに使用可能である場合にのみ表ロックを取得します。すぐに使用可能でない場合は、その時点ではロックを使用できないことを示すエラーが戻されます。
表ロックを取得するためにn秒まで待機する場合は、WAIT
n
を指定します。ここで、nは0より大きく、100000以下です。
n秒経過しても表ロックを使用できない場合は、その時点ではロックを使用できないことを示すエラーが戻されます。
ロックを取得するまで無限に待機する場合は、NOWAIT
およびWAIT
のいずれも指定しないでください。
データベースは表が使用可能になるまで無限に待機し、表をロックして制御を戻します。データベースでDML文と同時にDDL文を実行すると、タイムアウトやデッドロックが発生する場合があります。これらのタイムアウトやデッドロックがデータベースで検出されると、エラーが戻されます。
内容は次のとおりです。
参照: LOCK TABLE 文の構文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
共有(ROW
SHARE
MODE
)表ロック、および排他(ROW
EXCLUSIVE
MODE
)表ロックは最も高い同時実効性を提供します。次のような場合に使用します。
トランザクション内で表を更新する前に、別のトランザクションが共有表ロック、行共有表ロックまたは排他表ロックを割り込んで取得しないようにする必要がある場合。
別のトランザクションが共有表ロック、行共有表ロックまたは排他表ロックを割り込んで取得した場合、他のどのトランザクションも、そのロックしているトランザクションがコミットまたはロールバックされるまで、表を更新できません。
トランザクションで表を変更できるようになるまで、表の変更または削除を防止する必要がある場合。
SHARE
MODE
表ロックは非常に制限の多いデータ・ロックです。次のような場合に使用します。
トランザクションが表を問い合せるのみで、そのトランザクションの存続中一貫した一連の表データを必要とする場合。
表に対してSHARE
MODE
ロックを保持するすべてのトランザクションがコミットまたはロールバックするまで、ロックされている表を更新しようとする他のトランザクションを阻止できる場合。
他のトランザクションが、ロックされている表に対して同時にSHARE
MODE
表ロックを取得でき、またトランザクション・レベルの読取り一貫性のオプションを使用できる場合。
注意: 同じトランザクション内で、後から表を更新しないこともあります。ただし、複数のトランザクションが同じ表に対して共有表ロックを同時に保持している場合は(SELECT FOR UPDATE 文の結果によって行ロックが保持されている場合でも)、どのトランザクションも表を更新できません。したがって、同じ表に対する同時共有表ロックがよく発生する場合は、更新処理を継続できず、デッドロックがよく発生することになります。このような場合には、かわりに共有行排他ロックまたは排他表ロックを使用してください。 |
シナリオ: 表employees
およびbudget_tab
は、第3の表departments
の一貫した一連のデータを必要とします。特定の部門番号に関して、employees
およびbudget_tab
の情報を更新し、この2つのトランザクションの間にメンバーが部門に追加されないように保証するものとします。
解決方法: 例6-1のようにdepartments
表をSHARE
MODE
でロックします。departments
表の更新はまれなため、ロックしても他の多くのトランザクションの待機時間が長くなることはありません。
例6-1 SHARE MODEでのLOCK TABLE
-- Create and populate table: DROP TABLE budget_tab; CREATE TABLE budget_tab ( sal NUMBER(8,2), deptno NUMBER(4) ); INSERT INTO budget_tab (sal, deptno) SELECT salary, department_id FROM employees; -- Lock departments and update employees and budget_tab: LOCK TABLE departments IN SHARE MODE; UPDATE employees SET salary = salary * 1.1 WHERE department_id IN (SELECT department_id FROM departments WHERE location_id = 1700); UPDATE budget_tab SET sal = sal * 1.1 WHERE deptno IN (SELECT department_id FROM departments WHERE location_id = 1700); COMMIT; -- COMMIT releases lock
共有(SHARE
ROW
EXCLUSIVE
MODE
)表ロックは、次のような場合に使用します。
トランザクションで、特定の表についてトランザクション・レベルの読取り一貫性があり、かつ、ロックされている表が更新可能であることが必要な場合。
他のトランザクションによる(SELECT
FOR
UPDATE
を使用した)明示的な行ロックの可能性を考慮していない場合。ロック中のトランザクション内のUPDATE
およびINSERT
文が待機させられ、デッドロックが発生する可能性があります。
このように動作するトランザクションが1つのみ必要な場合。
排他(EXCLUSIVE
MODE
)表ロックは、次のような場合に使用します。
トランザクションが、ロックされている表にすぐに更新アクセスをする必要がある場合。トランザクションが排他表ロックを保持していると、他のトランザクションはロックされた表の中の特定の行をロックできません。
トランザクションがコミットまたはロールバックされるまで、ロックされた表に対してトランザクション・レベルの読取り一貫性が保持される場合。
低レベルのデータ同時実行性を意識する必要がなく、排他表ロックを要求するトランザクションを順次待機させて表を順番に更新させる場合。
Oracle Databaseに表ロック制御を任せると、アプリケーションに必要なプログラム・ロジックが少なくて済みます。ただし、表ロックを自分で管理する場合より制御範囲が小さくなります。
SET
TRANSACTION
ISOLATION
LEVEL
SERIALIZABLE
文またはALTER
SESSION
ISOLATION
LEVEL
SERIALIZABLE
文を発行すると、基礎となるロック・プロトコルを変更しなくても、ANSIのシリアライズ可能性を維持できます。この手法によって、ANSIのシリアライズ可能性を維持しながら表へ同時アクセスできます。表をロックすることによって、同時実行性が大幅に減少します。
参照:
|
これらのパラメータの設定変更は、インスタンスの停止時にのみ行ってください。複数インスタンスが単一データベースにアクセスする場合は、すべてのインスタンスでこれらのパラメータの設定を同じにする必要があります。
FOR
UPDATE
句を含むSELECT
文を使用すると、デフォルト・ロックをオーバーライドできます。この文は、選択されている行がその後の文で更新されることを想定し、(UPDATE
文のように)選択された行に対する明示的な行ロックを取得します。
SELECT
FOR
UPDATE
文を使用すると、その行を変更せずに行をロックできます。たとえば、『Oracle Database PL/SQL言語リファレンス』では、いくつかのトリガーで参照整合性を実装する方法を示しています。EMP_DEPT_CHECK
トリガーでは、参照される親キー値を含む行が、トランザクションの存続中は同じ値のままであることを保証するためにロックされます。親キーが更新または削除された場合、参照整合性違反になります。
SELECT
FOR
UPDATE
文は、ユーザーが1行以上の特定行のフィールドを変更できるような対話型プログラムでよく使用されます(時間がかかることがあります)。行を更新している対話型プログラム・ユーザーが常に1ユーザーのみであるように、行がロックされます。
カーソル定義にSELECT
FOR
UPDATE
文が使用される場合は、カーソルがオープンされるとき(最初のフェッチの前)に結果セット内の行がロックされます。行は、カーソルからフェッチされるときに、個別にロックされるわけではありません。カーソルをオープンしたトランザクションがコミットまたはロールバックされたときにのみ、ロックが解除されます。カーソルがクローズされるときには、ロックは解除されません。
SELECT
FOR
UPDATE
文の結果セット内の各行は個別にロックされます。SELECT
FOR
UPDATE
文は、競合している行ロックを他のトランザクションが解除するまで待機します。したがって、SELECT
FOR
UPDATE
文が表の行を多数ロックし、表に対して非常に多くの更新アクティビティが発生する場合は、EXCLUSIVE
表ロックを取得する方がパフォーマンスが改善する場合があります。
注意: 問合せの実行中に、SELECT FOR UPDATE に対する結果セットが変化する場合があります。たとえば、問合せ開始後に問合せで選択された列が更新されたり、行が削除された場合です。このような場合、SELECT FOR UPDATE は変更されなかった行でロックを取得し、このロックを使用して表の読取り一貫性スナップショットを取得してから、残りのロックを取得するために問合せを再起動します。
アプリケーションで |
デフォルトでは、要求された行ロックが取得されるまでSELECT
FOR
UPDATE
文は待機します。この動作を変更するには、SELECT
FOR
UPDATE
文でNOWAIT
、WAIT
、またはSKIP
LOCKED
句を使用します。このような句の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
表6-2に、LOCK TABLE
文およびFOR
UPDATE句を含むSELECT
文が使用された場合に、データの同時実行性、整合性および一貫性がOracle Databaseでどのように維持されるかを示します。簡略にするため、ORA-00054のメッセージ・テキスト(「リソース・ビジー、NOWAITが指定されていました。)は記載していません。
ユーザーが入力するテキストは太字で表示しています。
注意: ハイブリッド列圧縮(HCC)で圧縮された表では、DML文によって行ではなく圧縮単位がロックされます。特定のOracleストレージ・システムの機能であるHCCの詳細は、『Oracle Database概要』を参照してください。 |
表6-2 明示的なロックにおける同時実行性の例
トランザクション1 | タイム・ポイント | トランザクション2 |
---|---|---|
LOCK TABLE hr.departments IN ROW SHARE MODE; Statement processed. |
1 |
|
2 |
DROP TABLE hr.departments;
DROP TABLE hr.departments
*
ORA-00054
(トランザクション1によって表がロックされているため、排他DDLロックを取得できません。) |
|
3 |
LOCK TABLE hr.departments IN EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
4 |
SELECT location_id FROM hr.departments WHERE department_id = 20 FOR UPDATE OF location_id; LOCATION_ID ----------- DALLAS 1 row selected. |
|
UPDATE hr.departments SET location_id = 'NEW YORK' WHERE department_id = 20; (トランザクション2によって同じ行がロックされているため待機します。) |
5 |
|
6 |
ROLLBACK;
(行ロックを解放します。) |
|
1 row processed.
ROLLBACK;
|
7 |
|
LOCK TABLE hr.departments IN ROW EXCLUSIVE MODE; Statement processed. |
8 |
|
9 |
LOCK TABLE hr.departments IN EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
10 |
LOCK TABLE hr.departments IN SHARE ROW EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
11 |
LOCK TABLE hr.departments IN SHARE ROW EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
12 |
UPDATE hr.departments SET location_id = 'NEW YORK' WHERE department_id = 20; 1 row processed. |
|
13 |
ROLLBACK;
|
|
SELECT location_id FROM hr.departments WHERE department_id = 20 FOR UPDATE OF location_id; LOCATION_ID ----------- DALLAS 1 row selected. |
14 |
|
15 |
UPDATE hr.departments SET location_id = 'NEW YORK' WHERE department_id = 20; 1 row processed. (トランザクション1によって同じ行がロックされているため待機します。) |
|
ROLLBACK;
|
16 |
|
17 |
1 row processed. (競合するロックが解放されました。)
ROLLBACK;
|
|
LOCK TABLE hr.departments IN ROW SHARE MODE Statement processed. |
18 |
|
19 |
LOCK TABLE hr.departments IN EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
20 |
LOCK TABLE hr.departments IN SHARE ROW EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
21 |
LOCK TABLE hr.departments IN SHARE MODE; Statement processed. |
|
22 |
SELECT location_id FROM hr.departments WHERE department_id = 20; LOCATION_ID ----------- DALLAS 1 row selected. |
|
23 |
SELECT location_id FROM hr.departments WHERE department_id = 20 FOR UPDATE OF location_id; LOCATION_ID ----------- DALLAS 1 row selected. |
|
24 |
UPDATE hr.departments SET location_id = 'NEW YORK' WHERE department_id = 20; (トランザクション1に競合する表ロックがあるため待機します。) |
|
ROLLBACK;
|
25 |
|
26 |
1 row processed. (競合する表ロックが解放されました。)
ROLLBACK;
|
|
LOCK TABLE hr.departments IN SHARE ROW EXCLUSIVE MODE; Statement processed. |
27 |
|
28 |
LOCK TABLE hr.departments IN EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
29 |
LOCK TABLE hr.departments IN SHARE ROW EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
30 |
LOCK TABLE hr.departments IN SHARE MODE NOWAIT; ORA-00054 |
|
31 |
LOCK TABLE hr.departments IN ROW EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
32 |
LOCK TABLE hr.departments IN SHARE MODE NOWAIT; ORA-00054 |
|
33 |
SELECT location_id FROM hr.departments WHERE department_id = 20; LOCATION_ID ----------- DALLAS 1 row selected. |
|
34 |
SELECT location_id FROM hr.departments WHERE department_id = 20 FOR UPDATE OF location_id; LOCATION_ID ----------- DALLAS 1 row selected. |
|
35 |
UPDATE hr.departments SET location_id = 'NEW YORK' WHERE department_id = 20; (トランザクション1に競合する表ロックがあるため待機します。) |
|
UPDATE hr.departments SET location_id = 'NEW YORK' WHERE department_id = 20; (トランザクション2によって同じ行がロックされているため待機します。) |
36 |
(デッドロックが発生します。) |
Cancel operation.
ROLLBACK;
|
37 |
|
38 |
1 row processed. |
|
LOCK TABLE hr.departments IN EXCLUSIVE MODE; |
39 |
|
40 |
LOCK TABLE hr.departments IN EXCLUSIVE MODE; ORA-00054 |
|
41 |
LOCK TABLE hr.departments IN ROW EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
42 |
LOCK TABLE hr.departments IN SHARE MODE; ORA-00054 |
|
43 |
LOCK TABLE hr.departments IN ROW EXCLUSIVE MODE NOWAIT; ORA-00054 |
|
44 |
LOCK TABLE hr.departments IN ROW SHARE MODE NOWAIT; ORA-00054 |
|
45 |
SELECT location_id FROM hr.departments WHERE department_id = 20; LOCATION_ID ----------- DALLAS 1 row selected. |
|
46 |
SELECT location_id FROM hr.departments WHERE department_id = 20 FOR UPDATE OF location_id; (トランザクション1に競合する表ロックがあるため待機します。) |
|
UPDATE hr.departments SET department_id = 30 WHERE department_id = 20; 1 row processed. |
47 |
|
COMMIT;
|
48 |
|
49 |
0 rows selected. (トランザクション1の競合するロックが解放されました。) |
|
SET TRANSACTION READ ONLY;
|
50 |
|
SELECT location_id FROM hr.departments WHERE department_id = 10; LOCATION_ID ----------- BOSTON |
51 |
|
52 |
UPDATE hr.departments SET location_id = 'NEW YORK' WHERE department_id = 10; 1 row processed. |
|
SELECT location_id FROM hr.departments WHERE department_id = 10; LOCATION_ID ----------- BOSTON (トランザクション1には、未コミット・データが表示されません。) |
53 |
|
54 |
COMMIT;
|
|
SELECT location_id FROM hr.departments WHERE department_id = 10; LOCATION_ID ----------- BOSTON (トランザクション2がコミットした後でも同じ結果になります。) |
55 |
|
COMMIT;
|
56 |
|
SELECT location_id FROM hr.departments WHERE department_id = 10; LOCATION_ID ----------- NEW YORK (コミット済データが表示されます。) |
57 |
DBMS_LOCKパッケージのサブプログラムを起動することで、アプリケーションはOracle Lock Managementサービス(ユーザー・ロック)を使用できます。アプリケーションは、特定のモードのロックを要求し、同一または別のインスタンスの別のサブプログラムで認識できる一意の名前を付け、ロック・モードを変更し、解除できます。確保されるユーザー・ロックはOracle Databaseロックであるため、デッドロックの検出などのデータベース・ロックのすべての機能を持っています。分散トランザクションで使用されるユーザー・ロックは、
COMMIT
と同時に解除されるようになっていることを確認してください。解除されないと、検出されないデッドロックが発生する可能性があります。
参照: DBMS_LOCK パッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。 |
内容は次のとおりです。
次のような場合、ユーザー・ロックが役立ちます。
端末などの装置に対して排他的アクセスを可能にする場合
アプリケーション・レベルの読込みロックを適用する場合
ロックの解除を検出し、アプリケーションの終了後にクリーンアップする場合
アプリケーションを同期化して、順次処理を実行する場合
例6-2は、複数のユーザーが1つのデバイスにアクセスする必要がある場合に、競合が発生しないように保証するためのPro*COBOLプリコンパイラでのロックの使用方法を示しています。
例6-2 Pro*COBOLプリコンパイラによるロックの使用方法
****************************************************************** * Print Check * * Any cashier may issue a refund to a customer returning goods. * * Refunds under $50 are given in cash, more than $50 by check. * * This code prints the check. One printer is opened by all * * the cashiers to avoid the overhead of opening and closing it * * for every check, meaning that lines of output from multiple * * cashiers can become interleaved if you do not ensure exclusive * * access to the printer. The DBMS_LOCK package is used to * * ensure exclusive access. * ****************************************************************** CHECK-PRINT * Get the lock "handle" for the printer lock. MOVE "CHECKPRINT" TO LOCKNAME-ARR. MOVE 10 TO LOCKNAME-LEN. EXEC SQL EXECUTE BEGIN DBMS_LOCK.ALLOCATE_UNIQUE ( :LOCKNAME, :LOCKHANDLE ); END; END-EXEC. * Lock the printer in exclusive mode (default mode). EXEC SQL EXECUTE BEGIN DBMS_LOCK.REQUEST ( :LOCKHANDLE ); END; END-EXEC. * You now have exclusive use of the printer, print the check. ... * Unlock the printer so other people can use it EXEC SQL EXECUTE BEGIN DBMS_LOCK.RELEASE ( :LOCKHANDLE ); END; END-EXEC.
表6-3では、インスタンスで処理中のトランザクションのロック情報を表示する、Oracle Databaseの機能について説明しています。
表6-3 ロック情報の表示方法
Oracle Databaseは、デフォルトでは、同時に実行されるトランザクションの同じ表および同じデータ・ブロック内での行の修正、追加または削除を許可しています。トランザクションAが表を変更すると、トランザクションAがコミットされるまで、同時に実行しているトランザクションでは参照できません。トランザクションAが、(DML文またはSELECT
FOR
UPDATE
文を使用して)別のトランザクションBによってロックされている行を更新または削除しようとすると、トランザクションAのDML文は、トランザクションBがコミットまたはロールバックされるまでブロックされます。この同時実行性モデルは、より高度な同時実行性が提供されて、パフォーマンスが改善されるため、ほとんどのアプリケーションに適しています。
ただし、まれにシリアライズ可能なトランザクションが必要な場合もあります。シリアライズ可能トランザクションは、シリアル・モードで同時に実行します。シリアル・モードでは、同時トランザクションは、それらのトランザクションが順次(つまり一度に1つずつ)実行された場合に可能となるデータベースの変更のみが可能です。シリアライズ可能トランザクションの開始以降に、別のトランザクションにより変更されたデータを変更しようとすると、ORA-08177が発生します。
シリアライズ可能トランザクションがORA-08177で失敗した場合、アプリケーションは次のいずれかで対処できます。
そのポイントまで実行された作業をコミットします。
その他の様々な文を、トランザクション内の直前のセーブポイントまでロールバックした後に実行します。
トランザクションをロールバックし再度実行します。
トランザクションがトランザクション・スナップショットを取得するため、操作が成功する可能性が高くなります。
ヒント: トランザクションのロールバックおよび再実行によるパフォーマンスのオーバーヘッドを最小化するには、他の同時トランザクションと競合する可能性のあるDML文は、できるだけトランザクションの始めの方に置くようにしてください。 |
注意: シリアライズ可能トランザクションは遅延セグメント作成または時間隔パーティション化とともに動作しません。セグメントが作成されていない空の表、またはセグメントがまだない時間隔パーティション化された表のパーティションにデータを挿入しようとすると、エラーが発生します。 |
内容は次のとおりです。
ANSI/ISO SQL標準は3種類のトランザクションの相互作用を定義しています。
トランザクションが可能な相互作用の種類は分離レベルによって決まります。ANSI/ISO SQL標準は4レベルの分離を定義しています。表6-4に、各分離レベルで可能な相互作用の種類を示します。
表6-4 ANSI/ISO SQL分離レベルおよび可能なトランザクションの相互作用
分離レベル | 内容を保証しない読込み | 反復不能な読込み | 仮読込み |
---|---|---|---|
可能性あり |
可能性あり |
可能性あり |
|
可能性なし |
可能性あり |
可能性あり |
|
可能性なし |
可能性なし |
可能性あり |
|
可能性なし |
可能性なし |
可能性なし |
表6-5に、Oracle Databaseで用意されるANSI/ISO SQLトランザクション分離レベルを示します。
表6-5 Oracle Databaseで用意されるANSI/ISO SQL分離レベル
分離レベル | Oracle Databaseで用意される |
---|---|
いいえ、Oracle Databaseでは「内容を保証しない読込み」は許可されません。他のデータベース製品の中には、スループットの改善のために、この方法を使用するものもありますが、スループットの高いOracle Databaseでは不要です。 |
|
はい(デフォルト)。Oracle Databaseでは、問合せの始め(スナップショット時)にコミット済のデータのみを参照するため、 |
|
はい、トランザクション分離レベルを |
|
はい、トランザクション分離レベルを |
図6-1に、任意のトランザクション(SERIALIZABLE
またはREAD
COMMITTED
のいずれか)とシリアライズ可能トランザクションとの相互作用を示します。
トランザクション分離レベルをセッション全体のトランザクションに設定するには、ALTER
SESSION
文を使用します。『Oracle Database SQL言語リファレンス』を参照してください。
トランザクション分離レベルを特定のトランザクションに設定するには、SET
TRANSACTION
文のISOLATION
LEVEL
句を使用します。SET
TRANSACTION
文は『Oracle Database SQL言語リファレンス』で説明しているように、トランザクションの最初の文である必要があります。
注意: トランザクション分離レベルをSERIALIZABLE に設定する場合は、ALTER TABLE 文を使用して、INITRANS パラメータを3以上に設定する必要があります。多数のトランザクションが同じブロックを更新する表では、この値を大きくします。INITRANS の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
Oracle Databaseは、SERIALIZABLE
トランザクション内であっても読込みロックを使用しないため、あるトランザクションによって読み込まれたデータは、別のトランザクションでオーバーライドできます。そのため、アプリケーション・レベルでデータベースの整合性チェックを実行するトランザクションでは、読み込んだデータはトランザクション中には変更されないと考えないでください(そのような変更がトランザクションからはわからない場合も)。SERIALIZABLE
トランザクションを使用した場合でも、アプリケーション・レベルの整合性チェックのコードを十分注意して作成してください。
図6-2に、2つの表の間の参照整合性の親子関係を保持するために、アプリケーション・レベルでチェックを実行するトランザクションAとB (READ
COMMITTED
またはSERIALIZABLE
のいずれか)を示します。トランザクションAは、親表に問い合せて特定の主キー値を持つ行が存在するかどうかをチェックした後、対応する子行を子表に挿入します。トランザクションBは、子表に問い合せて特定の主キー値を持つ子行が存在しないことをチェックした後、親表から対応する親行を削除します。この場合、両方のトランザクションが読み込んだデータは、そのトランザクションが完了する前には変更されないものと想定しています(確認はしません)。
トランザクションAが実行した問合せのために、トランザクションBが親行を削除できなくなることはありません。トランザクションBが実行した問合せのために、トランザクションAが子行を挿入できなくなることもありません。したがって、次のことが起こる可能性があります。
トランザクションAは親表に問い合せて、指定した親行を確認します。
トランザクションBは子表に問い合せて、指定した親行が子行を持たないことを確認します。
指定した親行を確認して、トランザクションAは対応する子行を子表に挿入します。
指定した親行が子行を持たないことを確認して、トランザクションBは指定した親行を親表から削除します。
これで、トランザクションAが手順3で挿入した子行には親行がなくなりました。
このような結果は、AおよびBの両方がSERIALIZABLE
トランザクションであったとしても発生する可能性があります。どちらのトランザクションも、整合性チェックのために読み込んだデータに対する変更を他方が妨げないからです。
あるトランザクションが問い合せたデータが別のトランザクションにより同時に変更または削除されないようにするには、ANSI/ISO SQL標準のSERIALIZABLE
分離レベルが提供するよりも高いレベルのトランザクション分離が必要です。ただしOracle Databaseでは、次のことが可能です。
トランザクションAはSELECT
FOR
UPDATE
文を使用して、親行を問い合せてロックし、トランザクションBがその行を削除しないようにします。
SELECT
文のFOR
UPDATE
句の詳細は、 『Oracle Database SQL言語リファレンス』を参照してください。
トランザクションBは、処理手順を逆にして、トランザクションAが親行を見つけられないようにします(その結果、子行を挿入できなくなります)。つまりトランザクションBは次のことができます。
親行を削除します。
子表を問い合せます。
削除した親行に、子表内の子行がある場合は、親行の削除をロールバックします。
または、トリガーを使用して参照整合性を施行することもできます。トランザクションAが親表を問い合せるかわりに、子表で次を行う行レベルBEFORE
INSERT
トリガーを定義します。
SELECT
FOR
UPDATE
文を使用して親表を問い合せ、親行が存在するかどうかを確認することで、子行を挿入するトランザクションの処理中に、親行がデータベース内に残るようにします。
親行が存在しない場合、子行の挿入は拒否されます。
参照: トリガーを使用した親表と子表の間の参照整合性の維持の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。 |
トリガーによって発行されたSQL文は、そのトリガーを起動した文のコンテキスト内で実行されます(トリガー起動文とトリガー起動された文は同じデータベース状態を参照します)。そのため、READ
COMMITTED
トランザクションがトリガー起動文を実行する場合、トリガー起動された文は、トリガー起動文の実行開始時点のデータベースを参照します。SERIALIZABLE
トランザクションがトリガー起動文を実行する場合、トリガー起動された文は、そのトランザクションの開始時点のデータベースを参照します。いずれの場合も、トリガーで SELECT
FOR
UPDATE
を使用すると、参照整合性が正しく施行されます。
Oracle Databaseでは、READ
COMMITTED
およびSERIALIZABLE
という2つのトランザクション分離レベルが用意されています。どちらのレベルも高度な一貫性および同時実行性を提供し、競合を軽減し、実社会でのアプリケーション用に設計されています。この項では、2つの分離レベルを比較し、その選択方法を説明します。
内容は次のとおりです。
どの読込みにおいても、同じコミット済トランザクション集合によって書き込まれたデータが戻される場合、操作(問合せまたはトランザクション)は、「トランザクション集合整合である」といいます。トランザクション集合整合でない操作では、ある集合のトランザクションの変更が反映される読込みと、他のトランザクションによって行われた変更が反映される読込みが存在します。そのような操作では、そのデータベースは、コミットされたトランザクション集合が反映されていない状態のデータベースのように見えます。
内容は次のとおりです。
READ
COMMITTED
分離レベルでのOracle Databaseトランザクションは、問合せによって読み込まれたすべての行が、その問合せが始まる前にコミットされている必要があるため、文単位でのトランザクション集合整合です。
SERIALIZABLE
分離レベルでのOracle Databaseトランザクションは、SERIALIZABLE
トランザクション内のすべての文が、トランザクション開始時点のデータベースのイメージに対して実行されるため、トランザクション単位でのトランザクション集合整合です。
他のデータベース・システムでは、READ
UNCOMMITTED
分離レベルでの1回の問合せは、トランザクション集合整合ではありません。別のトランザクションによって行われた変更のサブセットしか見えないからです。たとえば、ディテール表とマスター表を結合すると、別のトランザクションによって挿入されたマスター・レコードを見ることはできますが、そのトランザクションによって挿入された対応するディテールは見えません(その逆も同じです)。READ
COMMITTED
分離レベルではこのような問題は回避されるため、読込みロック・システムより高い整合性が得られます。
読込みロック・システムでは、同時更新ができないようにするかわりに、REPEATABLE
READ
分離レベルによって、トランザクション・レベルではなく、文レベルでトランザクション集合の整合性が提供されます。仮読込み保護がないため、同一のトランザクションによる2つの問合せが、トランザクションの別の集合によってコミットされたデータを参照できます。これらのシステムでは、スループットに制限がありデッドロックされやすいSERIALIZABLE
分離レベルの場合のみ、トランザクション・レベルでのトランザクション集合の整合性が提供されます。
トランザクション分離レベルの選択は、パフォーマンスと整合性の必要性、およびアプリケーション・コーディング要件により異なります。同時実行性(トランザクションのスループット)と整合性はトレードオフの関係にあります。トランザクションの分離レベルの選択では、アプリケーションと作業負荷を考慮します。異なるトランザクションにはそれぞれ個別の分離レベルを選択できます。
多数のユーザーが、トランザクションを同時に次々に送る環境の場合、予期されるトランザクション到着頻度、応答時間要件、および必要な整合性の程度を考慮します。
READ
COMMITTED
分離レベルでは、一部のトランザクションについては(仮読込みおよび反復不能な読込みからの)一貫性のない結果が生成される可能性は多少高くなりますが、かなり高い同時実行性を提供できます。
SERIALIZABLE
分離レベルの場合は、仮読込みおよび反復不能な読込みから保護されているため、より高い整合性が提供され、読込み/書込みトランザクションが問合せを2回以上実行する場合にはこの分離レベルは重要です。ただし、SERIALIZABLE
分離レベルでは、アプリケーションが「このトランザクションのアクセスをシリアル化できません」というエラーの有無を確認する必要があり、多数の同時トランザクションが更新のために同じデータにアクセスする環境では、スループットはかなり低下する可能性があります。
6.6.3項で説明したように、READ
COMMITTED
またはSERIALIZABLE
トランザクションのいずれでも読込みは書込みをブロックしません。
表6-6に、READ
COMMITTED
トランザクションとSERIALIZABLE
トランザクションの類似点および相違点の概要を示します。
表6-6 コミット読込みトランザクションとシリアライズ可能トランザクションの比較
操作 | コミット読込み | シリアライズ可能 |
---|---|---|
内容を保証しない書込み |
可能性なし |
可能性なし |
内容を保証しない読込み |
可能性なし |
可能性なし |
反復不能な読込み |
可能性あり |
可能性なし |
仮読込み |
可能性あり |
可能性なし |
ANSI/ISO SQL 92への準拠 |
あり |
あり |
スナップショット読込み時間 |
文 |
トランザクション |
トランザクション集合の整合性 |
文レベル |
トランザクション・レベル |
行レベル・ロック |
あり |
あり |
読込みが書込みをブロック |
なし |
なし |
書込みが読込みをブロック |
なし |
なし |
異なる行の書込みが書込みをブロック |
なし |
なし |
同じ行の書込みが書込みをブロック |
あり |
あり |
阻止しているトランザクションの待機 |
あり |
あり |
エラー「このトランザクションのアクセスをシリアル化できません」の発生する可能性 |
なし |
あり |
阻止しているトランザクションの終了後のエラー |
なし |
なし |
阻止しているトランザクションのコミット後のエラー |
なし |
あり |
DDL文の非ブロック化とブロック化の違いは、表または索引のどちらか(表によって異なる)を変更するDDL文についてのみ重要です。
オブジェクトXに影響するDDL文をセッションが発行すると、Xを参照するすべての同時DML文がコミットされるかロールバックされるまで、セッションは待機します。
セッションが待機している間、同時セッションが新規のDML文を発行する可能性があります。DDL文が非ブロック化の場合、新規のDML文はただちに実行されます。DDL文がブロック化の場合、新規のDML文はDDL文の完了後に実行され、成功するかエラーが発生します。
DDL_LOCK_TIMOUT
パラメータはブロック化DDL文に影響します(が、非ブロック化DDL文には影響しません)。したがって、ブロック化DDL文の完了にはエラーORA-00054 (「リソース・ビジー。NOWAIT
が指定されているか、タイムアウトしました」)が伴う場合があります。DDL_LOCK_TIMOUT
パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。
表のパーティションに適用されるDDL文は、そのパーティションについてはブロック化、同じ表の他のパーティションについては非ブロック化です。
非ブロック化DDL文の一覧については、『Oracle Database SQL言語リファレンス』を参照してください。
注意: サプリメンタル・ロギングがデータベース・レベルで(マルチテナント・コンテナ・データベースまたはプラガブル・データベースについて)有効になっている場合、データベースでは非ブロック化DDL文がブロック化DDL文のように扱われます。サプリメンタル・ロギングの有効化および無効化の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
自律型トランザクション(AT)は、別のトランザクション(メイン・トランザクション(MT))によって開始される独立したトランザクションです。自律型トランザクションを使用すると、メイン・トランザクションを停止して、SQL操作を実行し、そのSQL操作をコミットまたはロールバックした後でメイン・トランザクションを再開できます。
たとえば、株式売買トランザクションでは、売買が成功するかどうかに関係なく、顧客情報のコミットが必要な場合があります。または、トランザクションがロールバックされた場合でも、エラー・メッセージをデバッグ表にログする必要がある場合もあります。自律型トランザクションを使用すると、これらのタスクを実行できます。
自律型トランザクションは自律型スコープ内、つまり、自律型ルーチン(AUTONOMOUS_TRANSACTION
プラグマでマークされるルーチン)の範囲内で実行されます。このコンテキストでは、ルーチンは次のいずれかになります。
スキーマレベル(ネストしていない)の無名PL/SQLブロック
スタンドアロン・サブプログラム、パッケージ・サブプログラムまたはネストしたサブプログラム
ADTのメソッド
非複合トリガー
自律型ルーチンで複数の自律型トランザクションをコミットできます。
図6-3に、メイン・トランザクション(proc1
)から自律型ルーチン(proc2
)へ制御が行き来する様子を示します。自律型ルーチンは、制御がメイン・トランザクションに戻る前に2つのトランザクション(AT1およびAT2)をコミットします。
自律型トランザクションの実行可能セクションに入ると、メイン・トランザクションが停止します。自律型トランザクションを終了すると、メイン・トランザクションが再開します。COMMIT
およびROLLBACK
によって、アクティブな自律型トランザクションは終了しますが、自律型トランザクションは終了しません。図6-3に示すとおり、1つのトランザクションが終了すると、次のSQL文が別のトランザクションを開始します。
自律型トランザクションの特長をさらに示します。
自律型トランザクションが加える変更は、メイン・トランザクションの状態または最終的な処理には依存しません。次に例を示します。
自律型トランザクションは、メイン・トランザクションによって加えられた変更を認識しません。
自律型トランザクションがコミットまたはロールバックしても、メイン・トランザクションの結果には影響しません。
自律型トランザクションが加える変更は、そのトランザクションがコミットした直後に他のトランザクションで参照できます。このため、メイン・トランザクションがコミットするまで待機しなくても、ユーザーは更新された情報にアクセスできます。
自律型トランザクションは他の自律型トランザクションを開始できます。
図6-4に、自律型トランザクションが従う実行順序の例を示します。
内容は次のとおりです。
参照: 自律型トランザクションの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。 |
この項では、自律型トランザクションの例を示します。
内容は次のとおりです。
例に示すとおり、自律型トランザクションおよびメイン・トランザクションを使用する場合は、4種類の結果が考えられます(表6-7を参照)。自律型トランザクションの結果とメイン・トランザクションの結果の間に依存性はありません。
図6-5に、顧客がある商品を注文する例を示します。購買契約が成立しなくても、その顧客の情報(名前、住所、電話番号など)は顧客情報表にコミットされます。
この例では、顧客は銀行口座から払戻しを実行しようとします。この処理で、メイン・トランザクションは2つの自律型トランザクション・スコープ(ATスコープ1またはATスコープ2)のいずれかを起動します。
このトランザクションで考えられる使用例を次に示します。
払戻しに十分な預金残高があり、銀行が払戻しに応じます。(図6-6を参照)。
払戻しに十分な預金残高はありませんが、この顧客には貸越し保護があるため、銀行が払戻しに応じます(図6-7を参照)。
払戻しに十分な預金残高はなく、この顧客には貸越し保護もありません。したがって、銀行は払戻しを差し止めます(図6-8を参照)。
自律型ルーチンを宣言するには、PRAGMA
AUTONOMOUS_TRANSACTION
を使用します。これは、PL/SQLコンパイラに対して、ルーチンを自律型としてマークするように指示します。
例6-3では、ファンクションbalance
が自律型です。
例6-3 パッケージ・サブプログラムの自律型としてのマーク
-- Create table for package to use:
DROP TABLE accounts;
CREATE TABLE accounts (account INTEGER, balance REAL);
-- Create package:
CREATE OR REPLACE PACKAGE banking AS
FUNCTION balance (acct_id INTEGER) RETURN REAL;
-- Additional functions and packages
END banking;
/
CREATE OR REPLACE PACKAGE BODY banking AS
FUNCTION balance (acct_id INTEGER) RETURN REAL IS
PRAGMA AUTONOMOUS_TRANSACTION;
my_bal REAL;
BEGIN
SELECT balance INTO my_bal FROM accounts WHERE account=acct_id;
RETURN my_bal;
END;
-- Additional functions and packages
END banking;
/
参照: PRAGMA AUTONOMOUS_TRANSACTION の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。 |
長時間にわたって実行されるトランザクションが記憶域割当てエラー状態によって中断されたときに、アプリケーションによって問題が発生した文を一時停止し、問題を修正した後でその文を再開することが可能です。この機能を、再開可能記憶域割当てといいます。この機能によって、時間がかかるロールバックを回避できます。また、操作を小さく分割したり、処理過程を追跡するコードを作成する必要がなくなります。
参照: 再開可能領域割当ての詳細は、『Oracle Database管理者ガイド』を参照してください。 |
内容は次のとおりです。
問合せ、DML操作および特定のDDL操作には、次のエラーの後で再開可能な記憶域割当てが含まれます。
ORA-01653などの領域不足エラー
ORA-01628などの領域制限エラー
ORA-01536などの領域割当てエラー
再開可能記憶域割当ては、操作がSQL文によって直接実行されているか、またはSQL*Loader、ストアド・サブプログラム、無名PL/SQLブロック、OCIStmtExecute
などのOCIコール内で実行されている場合に適用されます。
ディクショナリ管理された表領域では、ロールバック・セグメントの上限に達するか、エクステントの最大数に達した場合、索引または表の作成操作を再開できません。ローカル管理表領域および自動UNDO管理を、再開可能記憶域割当てと組み合せて使用してください。
記憶域割当てエラーのためにアプリケーション内の文が一時停止された場合、アプリケーションはエラー・コードを受信しません。このため、アプリケーションでAFTER
SUSPEND
トリガーを使用するか、またはDBAが一時停止された文を定期的に確認する必要があります。
問題が(通常DBAによって)修正されると、一時停止された文は自動的に実行を再開します。タイムアウト周期が終了するまでに問題が修正されなかった場合は、その文によってSERVERERROR
例外が発生します。
内容は次のとおりです。
アプリケーションで、AFTER
SUSPEND
トリガーはDBMS_RESUMABLE
パッケージ内のサブプログラムを起動して、問題に関する情報を取得できます(『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照)。次にトリガーはオペレータに電子メールなどを使用して情報を送信できます。
トリガー自体の中で領域不足エラーが発生する可能性を減らすには、トリガーを自律型トランザクションとして宣言します。自律型トランザクションとして、トリガーはSYSTEM
表領域内のロールバック・セグメントを使用します。一時停止された文が保持するロックによってトリガーにデッドロック状態が発生した場合、そのトリガーは終了され、アプリケーションは文の一時停止が発生しなかった場合の本来のエラー状態を受信します。トリガーによって領域不足状態が発生した場合、そのトリガーおよび一時停止された文は両方ともロールバックされます。ロールバックを回避するには、トリガー内の例外ハンドラを使用し、文が再開されるまで待ちます。
トリガーの一般的な情報は、『Oracle Database PL/SQL言語リファレンス』を参照してください。
例6-4のトリガーは、データベース内の記憶域エラーを処理します。いくつかのエラーでは、このトリガーは文を終了し、エラーに関する警告を電子メールを使用してDBAに通知します。他の一時的なエラーでは、8時間以内に記憶域の問題が解決していることを想定して、8時間後に文を再開するように指定しています。この例を実行するには、SYSDBA
としてデータベースに接続する必要があります。
例6-4 AFTER SUSPENDトリガーによる一時停止された記憶域割当ての処理
-- Create table used by trigger body DROP TABLE rbs_error; CREATE TABLE rbs_error ( SQL_TEXT VARCHAR2(64), ERROR_MSG VARCHAR2(64), SUSPEND_TIME VARCHAR2(64) ); -- Resumable Storage Allocation CREATE OR REPLACE TRIGGER suspend_example AFTER SUSPEND ON DATABASE DECLARE cur_sid NUMBER; cur_inst NUMBER; err_type VARCHAR2(64); object_owner VARCHAR2(64); object_type VARCHAR2(64); table_space_name VARCHAR2(64); object_name VARCHAR2(64); sub_object_name VARCHAR2(64); msg_body VARCHAR2(64); ret_value BOOLEAN; error_txt VARCHAR2(64); mail_conn UTL_SMTP.CONNECTION; BEGIN SELECT DISTINCT(SID) INTO cur_sid FROM V$MYSTAT; cur_inst := USERENV('instance'); ret_value := DBMS_RESUMABLE.SPACE_ERROR_INFO (err_type, object_owner, object_type, table_space_name, object_name, sub_object_name); IF object_type = 'ROLLBACK SEGMENT' THEN INSERT INTO rbs_error (SELECT SQL_TEXT, ERROR_MSG, SUSPEND_TIME FROM DBA_RESUMABLE WHERE SESSION_ID = cur_sid AND INSTANCE_ID = cur_inst); SELECT ERROR_MSG INTO error_txt FROM DBA_RESUMABLE WHERE SESSION_ID = cur_sid AND INSTANCE_ID = cur_inst; msg_body := 'Space error occurred: Space limit reached for rollback segment ' || object_name || ' on ' || to_char(SYSDATE, 'Month dd, YYYY, HH:MIam') || '. Error message was: ' || error_txt; mail_conn := UTL_SMTP.OPEN_CONNECTION('localhost', 25); UTL_SMTP.HELO(mail_conn, 'localhost'); UTL_SMTP.MAIL(mail_conn, 'sender@localhost'); UTL_SMTP.RCPT(mail_conn, 'recipient@localhost'); UTL_SMTP.DATA(mail_conn, msg_body); UTL_SMTP.QUIT(mail_conn); DBMS_RESUMABLE.ABORT(cur_sid); ELSE DBMS_RESUMABLE.SET_TIMEOUT(3600*8); END IF; COMMIT; END; /
アプリケーションがAFTER
SUSPEND
トリガーを使用しない場合、DBAは静的データ・ディクショナリ・ビューDBA_RESUMABLE
(『Oracle Databaseリファレンス』を参照)を使用して、一時停止された文を定期的に確認する必要があります。
DBAは動的パフォーマンス・ビューV$_SESSION_WAIT
(『Oracle Databaseリファレンス』参照)から追加の情報を取得することができます。