ヘッダーをスキップ

Oracle Database アプリケーション開発者ガイド-基礎編
10gリリース2(10.2)

B19248-02
目次
目次
索引
索引

戻る 次へ

2 アプリケーション開発者用のSQL処理

この章では、Oracle DatabaseでのSQL文の処理方法について説明します。この章を読む前に、『Oracle Database概要』の「SQLの処理」の項を読んでおいてください。

内容は次のとおりです。

操作のトランザクションへのグループ化

この項の内容は次のとおりです。

トランザクションへの操作のグループ化方法の決定

一般に、Oracle Databaseのプログラム・インタフェースを使用するアプリケーション設計者のみが、どのタイプのアクションを1つのトランザクションとしてグループ化するかを考慮します。トランザクションのグループ化方法を決定する際は、次の規則に従います。

たとえば、口座間で預金を移動できるWebアプリケーションを作成すると仮定します。このトランザクションには、一方の口座の借方への記帳(1つのSQL文で実行)ともう一方の口座の貸方への記帳(もう1つのSQL文で実行)が含まれています。2つの文で1つの作業単位となり、両方が成立するか両方が不成立かのいずれかです。つまり、借方を伴わない貸方はコミットしません。一方の口座への新規預金など、関連のないアクションは、同じトランザクションに含めません。

トランザクションのパフォーマンスの改善

アプリケーション開発者は、パフォーマンスが改善可能か検討する必要があります。アプリケーションの設計および作成では、次のパフォーマンス要件を考慮する必要があります。

トランザクションのコミット

トランザクションをコミットするには、COMMIT文を使用します。次の2つの文は同等で、現行のトランザクションをコミットします。

COMMIT WORK;
COMMIT;

COMMIT文には、コミットされるトランザクションに関する情報を示すコメントを指定したCOMMENTパラメータを含めることができます。このオプションは、分散トランザクションをコミットするときに、トランザクションの起点に関する情報を含める場合に有効です。

COMMIT COMMENT 'Dallas/Accts_pay/Trans_type 10B';

コミットREDO動作の管理

トランザクションがデータベースを更新するとき、この更新に対応するREDOエントリが生成されます。トランザクションが完了するまで、このREDOはOracle Databaseによりメモリにバッファリングされます。トランザクションがコミットされると、それに応じてログ・ライター(LGWR)・プロセスがトランザクション内のすべての変更の蓄積されたREDOをディスクに書き込みます。デフォルトでは、REDOは、コールがクライアントに戻される前に、Oracle Databaseによりディスクに書き込まれます。この動作のためにアプリケーションはREDOがディスクに永続的に書き込まれるのを待機する必要があり、コミットに待機時間が発生します。

高いトランザクション・スループットを必要とするアプリケーションを作成する場合を考えます。コミットでの待機時間を短くするためにコミットの永続性を放棄してもよい場合は、デフォルトのCOMMITオプションを変更して、Oracle DatabaseでデータがオンラインREDOログへ書き込まれるのをアプリケーションが待機しなくて済むようにできます。

Oracle Databaseでは、アプリケーションのニーズに応じてコミットREDOの処理を変更できます。コミット動作は次の場所で変更できます。

COMMIT文のオプションを使用すると、初期化パラメータの現行の設定がオーバーライドされます。表2-1に、このどちらかで設定可能な、REDO永続オプションの説明を示します。

表 2-1    コミットREDO管理用の初期化パラメータおよびCOMMITオプション 
オプション  指定内容 

WAIT 

コミットに対応するREDOがオンラインREDOログに永続的に書き込まれるまで、コミットは成功として戻されません(デフォルト)。 

NOWAIT 

コミットは、REDOがオンラインREDOログに書き込まれるまで待機せずにアプリケーションに戻されます。 

IMMEDIATE 

ログ・ライター・プロセスは、コミットとともに即時にREDOを書き込みます(デフォルト)。つまり、このオプションにより、ディスクI/Oが発生します。 

BATCH 

Oracle Databaseにより、REDOがバッファリングされます。ログ・ライター・プロセスは、特定の時間内にREDOをディスクに書き込むことが許可されます。 

次の例は、初期化パラメータ・ファイルでコミット動作をBATCHおよびNOWAITに設定する方法を示しています。

COMMIT_WRITE = BATCH, NOWAIT

コミット動作は、次の例のようにALTER SYSTEMを実行することにより、システム・レベルで変更できます。

ALTER SYSTEM SET COMMIT_WRITE = BATCH, NOWAIT

初期化パラメータの設定後、オプションを指定していないCOMMIT文は、パラメータのオプションの設定に準拠するようになります。また、次の例のように、COMMIT文で直接オプションを指定することにより、現行の初期化パラメータの設定をオーバーライドできます。

COMMIT WRITE BATCH NOWAIT

どちらの例でも、コミット時に即時にログ・ライターがREDOをオンラインREDOログへ書き込む必要がないこと、および、REDOがディスクへ書き込まれるのを待機しないことが、アプリケーションで指定されています。


注意

分散トランザクションの場合、デフォルトのIMMEDIATEおよびWAITは変更できません。 


OCIを使用するアプリケーションの場合、アプリケーション内でOCITransCommit()ファンクションに次のフラグを設定することにより、REDO動作を変更できます。

NOWAITおよびBATCHオプションの指定は、影響の反映されやすい小さいウィンドウの場合、Oracle Databaseでトランザクションがロールバックされてもアプリケーションではコミット済として表示される可能性がありますので注意してください。アプリケーションは、次のような状況に対応できる必要があります。

トランザクションのロールバック

トランザクションの全体または一部を(セーブポイントまで)ロールバックするには、ROLLBACK文を使用します。たとえば、次の文はどちらも、現行のトランザクション全体をロールバックします。

ROLLBACK WORK;
ROLLBACK;

ROLLBACKコマンドのWORKオプションには、何も機能はありません。

現行のトランザクション内に定義されたセーブポイントまでロールバックするには、ROLLBACKコマンドのTOオプションを使用する必要があります。たとえば、次の文はいずれもPOINT1という名前のセーブポイントまで現行のトランザクションをロールバックします。

SAVEPOINT Point1;
...
ROLLBACK TO SAVEPOINT Point1;
ROLLBACK TO Point1;

トランザクションのセーブポイントの定義

トランザクション内にセーブポイントを定義するには、SAVEPOINTコマンドを使用します。次の文は、現行のトランザクション内にADD_EMP1という名前のセーブポイントを作成します。

SAVEPOINT Add_emp1;

前のセーブポイントと同じ識別子で2番目のセーブポイントを作成すると、前のセーブポイントが消去されます。セーブポイントを作成した後は、そのセーブポイントまでロールバックできます。

セッション当たりのアクティブ・セーブポイントの数に制限はありません。アクティブ・セーブポイントとは、最後のコミットまたは最後のロールバック以降に指定されたセーブポイントのことです。

COMMIT、SAVEPOINTおよびROLLBACKの例

表2-2に、トランザクション内でのCOMMIT文、SAVEPOINT文およびROLLBACK文の一連のSQL文を示し、それらの使用方法を具体的に説明します。

表 2-2    COMMIT、SAVEPOINTおよびROLLBACKの使用方法 
SQL文  結果 

SAVEPOINT a; 

このトランザクションの最初のセーブポイント 

DELETE...; 

このトランザクションの最初のDML文 

SAVEPOINT b; 

このトランザクションの2番目のセーブポイント 

INSERT INTO...; 

このトランザクションの2番目のDML文 

SAVEPOINT c; 

このトランザクションの3番目のセーブポイント 

UPDATE...; 

このトランザクションの3番目のDML文 

ROLLBACK TO c; 

UPDATE文がロールバックされ、セーブポイントCは定義されたままになります。 

ROLLBACK TO b; 

INSERT文がロールバックされ、セーブポイントCは失われます。セーブポイントBは定義されたままです。 

ROLLBACK TO c; 

ORA-01086エラー「セーブポイント'C'は設定されていません」 

INSERT INTO...; 

このトランザクションの新しいDML文 

COMMIT; 

最初のDML文(DELETE文)および最後のDML文(2番目のINSERT文)によって行われたすべてのアクションがコミットされます。

トランザクションのその他すべての文(2番目および3番目の文)はCOMMITの前にロールバックされています。セーブポイントAは、すでにアクティブではありません。 

読取り専用トランザクションでの反復可能読取りの保証

デフォルトでは、Oracle Databaseの一貫性モデルは、文レベルの読取り一貫性は保証しますが、トランザクション・レベルの読取り一貫性(反復可能読取り)は保証しません。トランザクション・レベルの読取り一貫性が必要で、トランザクションが更新を必要としない場合は、読取り専用トランザクションを指定できます。トランザクションを読取り専用に指定すると、どのデータベース表に対しても必要な数の問合せを実行でき、その読取り専用トランザクション内の各問合せの結果は、特定の1つの時点における一貫性が保たれています。

読取り専用トランザクションでは、トランザクション・レベルの読取り一貫性を保持するためにデータ・ロックを加えることはありません。文レベルの読取り一貫性のために使用されるマルチバージョンの一貫性モデルが、トランザクション・レベルの読取り一貫性を保持するために使用されます。すべての問合せは、読取り専用トランザクションが開始したときに決定されたシステム変更番号(SCN)の情報を戻します。データがロックされないため、読取り専用トランザクションが問い合せているデータを他のトランザクションが同時に問い合せたり更新することができます。

実行時間の長い問合せでは、読取り一貫性操作に必要なUNDO情報が無効になったためにエラーが発生することがあります。これは、アクティブなトランザクションによって、コミット済みUNDOブロックが上書きされた場合に起こります。自動UNDO管理を行うと、UNDO領域を再利用できる時点、つまり、UNDO情報の保存期間を明示的に制御できます。データベース管理者は、パラメータUNDO_RETENTIONを使用して保存期間を指定できます。

関連項目

実行時間の長い問合せおよび再開可能領域割当ての詳細は、『Oracle Database管理者ガイド』を参照してください。 

たとえば、UNDO_RETENTIONを30分に設定すると、システムのすべてのコミット済UNDO情報は、最低30分間保持されます。この設定により、通常の環境下であれば、実行時間が30分以内の問合せでOERエラー「スナップショットが古すぎます。」が発生することはなくなります。

読取り専用トランザクションは、READ ONLYオプションを含むSET TRANSACTION文で始まります。次に例を示します。

SET TRANSACTION READ ONLY;

SET TRANSACTION文は、新しいトランザクションの最初の文である必要があります。任意のDML文(問合せを含む)または他のDDL以外の文(たとえば、SET ROLE)がSET TRANSACTION READ ONLY文より前に指定されていると、エラーが戻されます。SET TRANSACTION READ ONLY文が正常に実行されると、そのトランザクションでは、SELECT文(FOR UPDATE 句なし)、COMMIT文、ROLLBACK文またはDML以外の文(たとえば、SET ROLEALTER SYSTEMLOCK TABLE)のみが使用できます。これら以外の文では、エラーが戻されます。COMMIT文、ROLLBACK文またはDDL文によって、読取り専用トランザクションは終了します(DDL文によって、読取り専用トランザクションは暗黙的にコミットされ、それ自身のトランザクション内でコミットされます)。

アプリケーションでのカーソルの使用

PL/SQLでは、1行のみ戻す問合せも含めて、すべてのSQLデータ操作文に対してカーソルを暗黙的に宣言します。複数行を戻す問合せの場合、カーソルを明示的に宣言して行を別々に処理できます。

カーソルは、特定のプライベートSQL領域へのハンドルです。カーソルは、特定のプライベートSQL領域の名前と考えることができます。PL/SQLカーソル変数を使用すると、ストアド・プロシージャから複数の行を取得できます。カーソル変数を使用すると、3GLアプリケーション内のパラメータとしてカーソルを渡すことができます。カーソル変数の詳細は、『PL/SQLユーザーズ・ガイドおよびリファレンス』を参照してください。

ほとんどのOracle Databaseユーザーは、データベース・ユーティリティの自動カーソル処理を使用しますが、アプリケーション設計者は、プログラム・インタフェースを使用した方がカーソルを制御しやすくなります。アプリケーション開発では、カーソルはプログラムで使用できる名前付きのリソースであり、アプリケーションに埋め込まれたSQL文の解析に特に有効です。

カーソルの宣言およびオープン

1つのセッションで同時にオープンできるカーソルの総数に絶対的な制限はありませんが、次の2つの制約があります。

プリコンパイラ・プログラムに対して明示的にカーソルを作成すると、アプリケーションのチューニング時に有効です。たとえば、カーソル数を増加させると、解析頻度が削減されパフォーマンスが改善されることがよくあります。ある時点で必要となるカーソル数がわかっている場合、その数のカーソルを必ず同時にオープンできるように宣言できます。

カーソルを使用した文の再実行

各ステージの実行後、カーソルはそのSQL文に関する十分な情報を保持しているため、同じカーソルに他のSQL文が対応付けられていないかぎり、最初から実行しなおさなくてもその文を再実行できます。文は、解析ステージを含めなくても再実行できます。

カーソルをいくつかオープンすることによって、いくつかのSQL文の解析済表現を保存できます。同じSQL文を繰り返し実行する場合、記述手順、定義手順、バインド手順または実行手順から開始することができ、カーソルのオープンおよび解析を繰り返す必要がなくなります。

あるカーソルのパフォーマンス特性を理解するために、DBAは、V$SQLカタログ・ビューを使用して、そのカーソルが表現する問合せのテキストを取得できます。元の問合せに対するEXPLAIN PLANの結果は、問合せの実際の処理方法とは異なる場合があります。そのためDBAは、V$SQL_PLANV$SQL_PLAN_STATISTICSおよびV$SQL_PLAN_STATISTICS_ALLカタログ・ビューを調べることによってより正確な情報を取得できます。

カーソルのクローズ

カーソルのクローズとは、関連付けられているプライベート領域に現在ある情報が失われ、そのメモリーの割当てが解除されることです。カーソルは、一度オープンされると次のいずれかが発生するまでクローズされません。

カーソルの取消し

カーソルを取り消すと、現在のフェッチからリソースが解放されます。対応付けられたプライベート領域に現在ある情報は失われますが、カーソルはオープンしたままになり、解析され、バインド変数に対応付けられます。


注意

Pro*C/C++またはPL/SQLを使用してカーソルを取り消すことはできません。 


関連項目

カーソルの取消しの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。 

明示的なデータのロック

Oracle Databaseでは、データの同時実行性、整合性、および文レベル読取り一貫性を保持するために、常に必要なロックが実行されます。これらのデフォルト・ロック・メカニズムはオーバーライドできます。たとえば、次のような場合に、Oracle Databaseのデフォルト・ロックのオーバーライドが必要になります。

自動ロック・メカニズムは、トランザクション・レベルでオーバーライドできます。次のSQLコマンドを含むトランザクションは、Oracle Databaseのデフォルト・ロックをオーバーライドします。

これらの文によって取得されるロックは、トランザクションのコミット後またはロールバック後に解除されます。

次の項では、Oracle Databaseのデフォルト・ロックをオーバーライドするために使用できる各オプションを説明します。DML_LOCKS初期化パラメータによって、使用可能なDMLロックの最大数が決定されます。

関連項目

パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。 

通常、デフォルト値には十分な値が設定されていますが、手動ロックを追加して使用する際に、この値を大きくする必要がある場合があります。


注意

いずれかのレベルでOracle Databaseのデフォルト・ロックをオーバーライドする場合は、新しいロック手順が正しく動作することを確認する必要があります。データ整合性が保証されていること、データ同時実行性が許容されていること、およびデッドロックの可能性がないこと、またはデッドロックが適切に処理されていることを確認してください。 


ロック方法の選択

LOCK TABLE文が実行されると、トランザクションは指定された表ロックを明示的に取得します。LOCK TABLE文は、デフォルト・ロックを手動でオーバーライドします。ビューに対してLOCK TABLE文が発行されると、基礎となる実表がロックされます。次の文は、EMP_TAB表およびDEPT_TAB表を含むトランザクションにかわって、この2つの表に対する排他表ロックを取得します。

LOCK TABLE Emp_tab, Dept_tab
    IN EXCLUSIVE MODE NOWAIT;

ロック・モードが同じ場合は、ロックする表またはビューを複数指定できます。ただし、1つのLOCK TABLE文に指定できるロック・モードは1つのみです。


注意

表がロックされると、その表のすべての行がロックされます。他のユーザーは、その表を変更できません。 


また、ロックの取得を待つか待たないかも指示できます。NOWAITオプションを指定すると、表ロックがすぐに使用可能である場合にのみ表ロックを取得します。すぐに使用可能でない場合は、その時点ではロックが使用できないことを示すエラーが戻されます。その場合は、後でリソースに対するロックを再試行できます。NOWAITを指定しないと、要求した表ロックが取得されるまで、トランザクションは処理を続行しません。表ロックに対する待ち時間が長すぎる場合は、そのロック操作を取り消して、後で再試行できます。このロジックは、アプリケーション内に作成できます。

ROW SHAREおよびROW EXCLUSIVEモードでロックする場合

LOCK TABLE Emp_tab IN ROW SHARE MODE;
LOCK TABLE Emp_tab IN ROW EXCLUSIVE MODE;

行共有(ROW SHARE)表ロックおよび行排他(ROW EXCLUSIVE)表ロックは、最も高い同時実行性を提供します。次のような場合に使用します。

SHAREモードでロックする場合

LOCK TABLE Emp_tab IN SHARE MODE;

共有表(SHARE)ロックは非常に制限の多いデータ・ロックです。次のような場合に使用します。

たとえば、2つの表EMP_TABおよびBUDGET_TABには、第3の表DEPT_TABの一貫した一連のデータが必要であると仮定します。特定の部門番号に関して、2つの表の情報を更新し、この2つのトランザクションの間に新しいメンバーが部門に追加されないように保証するものとします。

この使用例はきわめてまれな場合ですが、次の例で示すように、SHARE MODEDEPT_TAB表をロックすることによって対処できます。DEPT_TAB表の更新はまれなため、ロックしても他の多くのトランザクションの待ち時間が長くなることはありません。


注意

次のようなデータ構造を設定しないと機能しない例もあります。

CREATE TABLE dept_tab(
deptno NUMBER(2) NOT NULL,
dname VARCHAR2(14),
loc VARCHAR2(13));

CREATE TABLE emp_tab (
empno NUMBER(4) NOT NULL,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2));

CREATE TABLE Budget_tab (
totsal NUMBER(7,2),
deptno NUMBER(2) NOT NULL);
 

LOCK TABLE Dept_tab IN SHARE MODE;
UPDATE Emp_tab
    SET sal = sal * 1.1
    WHERE deptno IN 
      (SELECT deptno FROM Dept_tab WHERE loc = 'DALLAS');
UPDATE Budget_tab
    SET Totsal = Totsal * 1.1
    WHERE Deptno IN
      (SELECT Deptno FROM Dept_tab WHERE Loc = 'DALLAS');

COMMIT; /* This releases the lock */

SHARE ROW EXCLUSIVEモードでロックする場合

LOCK TABLE Emp_tab IN SHARE ROW EXCLUSIVE MODE;

共有行排他(SHARE ROW EXCLUSIVE)表ロックは、次のような場合に使用します。

EXCLUSIVEモードでロックする場合

LOCK TABLE Emp_tab IN EXCLUSIVE MODE;

排他(EXCLUSIVE)表ロックは、次のような場合に使用します。

必要な権限

自スキーマ内の表に対しては、どの種類の表ロックでも自動的に取得できます。他スキーマ内の表に対して表ロックを取得するには、LOCK ANY TABLEシステム権限またはその表に対する(SELECTUPDATEなどの)オブジェクト権限が必要です。

Oracle Databaseによる表ロック制御

Oracle Databaseに表ロック制御を任せると、アプリケーションに必要なプログラム・ロジックが少なくて済みます。ただし、表ロックを自分で管理する場合より制御範囲が小さくなります。

SET TRANSACTION ISOLATION LEVEL SERIALIZABLEコマンドまたはALTER SESSION ISOLATION LEVEL SERIALIZABLEコマンドを発行すると、基礎となるロック・プロトコルを変更しなくても、ANSIのシリアライズ可能性を維持できます。この手法によって、ANSIのシリアライズ可能性を維持しながら表へ同時アクセスできます。表をロックすることによって、同時実行性が大幅に減少します。

関連項目

  • SET TRANSACTION文の詳細は、『Oracle Database SQLリファレンス』を参照してください。

  • ALTER SESSION文の詳細は、『Oracle Database SQLリファレンス』を参照してください。

 

インスタンスが停止されているときにのみ、これらのパラメータの設定を変更可能です。複数インスタンスが単一データベースにアクセスする場合は、すべてのインスタンスでこれらのパラメータの設定を同じにする必要があります。

明示的な行ロック

FOR UPDATE句を含むSELECT文を使用すると、デフォルト・ロックをオーバーライドできます。この文は、選択されている行がその後の文で更新されることを想定し、(UPDATE文のように)選択された行に対する明示的な行ロックを取得します。

SELECT... FOR UPDATE文を使用すると、実際にその行を変更せずに行をロックできます。たとえば、第9章「トリガーのコーディング」では、いくつかのトリガーで参照整合性を実装する方法を示しています。EMP_DEPT_CHECKトリガー(12-41ページの「子表に対する外部キー・トリガー」を参照)では、参照される親キー値を含む行が、トランザクションの存続中は同じ値のままであることを保証するためにロックされます。親キーが更新または削除された場合、参照整合性違反になります。

SELECT... FOR UPDATE 文は、ユーザーが1行以上の特定行のフィールドを変更できるような対話型プログラムでよく使用されます(時間がかかることがあります)。行を更新している対話型プログラム・ユーザーが常に1ユーザーのみであるように、行がロックされます。

カーソル定義にSELECT... FOR UPDATE文が使用される場合は、カーソルがオープンされるとき(最初のフェッチの前)に結果セット内の行がロックされます。行は、カーソルからフェッチされるときに、個別にロックされるわけではありません。カーソルをオープンしたトランザクションがコミットまたはロールバックされたときにのみ、ロックが解除されます。カーソルがクローズされるときには、ロックは解除されません。

SELECT... FOR UPDATE文の結果セット内の各行は、個別にロックされます。SELECT... FOR UPDATE文は、競合している行ロックを他のトランザクションが解除するまで待機します。 したがって、SELECT... FOR UPDATE 文が表の行を多数ロックし、表に対して非常に多くの更新アクティビティが発生する場合は、EXCLUSIVE表ロックを取得する方がパフォーマンスが改善する場合があります。


注意

問合せの実行中に、SELECT... FOR UPDATEに対する結果セットが変化する場合があります。たとえば、問合せ開始後に問合せで選択した列が更新されたり、行が削除された場合です。 このような場合、SELECT... FOR UPDATEは 変更されなかった行でロックを取得し、このロックを使用して表の新しい読取り一貫性スナップショットを取得してから、残りのロックを取得するために問合せを再起動します。

行がランダムにロックされたときにこの処理が実行されると、DML操作を使用して表を同時に問い合せているセッション間にデッドロックが発生する場合があります。このようなデッドロックの発生を防ぐために、表の同時DMLが問合せの結果セットに影響しないようにアプリケーションを設計してください。無理な場合は、アプリケーションでの問合せをシリアライズするという方法もあります。  


SELECT... FOR UPDATEを使用して行ロックを取得する場合は、NOWAITオプションを指定してロック取得時の待機を避けることができます。すぐにロックが取得できない場合は、この時点ではロックできないことを示すエラーが戻されます。その行のロックは、後で再試行できます。

デフォルトでは、要求された行ロックが取得されるまでトランザクションは待機します。行ロックに対する待ち時間が長すぎる場合は、そのロック操作を取り消して後で再試行するロジックを、アプリケーションに作成できます。

ユーザー・ロック

DBMS_LOCKパッケージをコールすることで、アプリケーションでOracle Lock Managementサービスを使用できます。特定のモードのロックを要求し、同一のインスタンスまたは別のインスタンスの別のプロシージャで認識できる一意の名前を付け、ロック・モードを変更し、解除することができます。確保されるユーザー・ロックはOracle Databaseロックと同一であるため、デッドロックの検出などのデータベース・ロックのすべての機能を持っています。分散トランザクションで使用されるユーザー・ロックは、COMMITと同時に解除されるようになっていることを確認してください。解除されないと、検出されないデッドロックが発生する可能性があります。

関連項目

DBMS_LOCKパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。 

ユーザー・ロックを使用する場合

次のような場合、ユーザー・ロックを使用します。

ユーザー・ロックの例

次のPro*COBOLプリコンパイラの例は、複数のユーザーが1つの装置にアクセスする必要がある場合に、競合が発生しないように保証するためのロックの使用方法を示しています。

***************************************************************** 
* 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. The one printer is opened by all  * 
* the cashiers to avoid the overhead of opening and closing it  * 
* for every check. This means that lines of output from multiple* 
* cashiers could become interleaved if we don't 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. 
*   We 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. 

ロックの表示および監視

表2-3で、インスタンスで処理中のトランザクションに対するロック情報を表示するためのOracle Databaseの機能を説明します。

表 2-3    ロック情報の表示方法 
ツール  説明 

Oracle Enterprise Manager 10g Database Control 

「データベース・パフォーマンス」ページの「その他の監視リンク」セクションで、「データベース・ロック」をクリックしてユーザー・ブロック、ブロッキング・ロック、またはすべてのデータベース・ロックの詳細なリストを表示します。詳細は、『Oracle Database 2日でデータベース管理者』を参照してください。 

UTLLOCKT.SQL 

UTLLOCKT.SQLスクリプトは、ツリー構造の簡単なロック待機グラフを表示します。スクリプトの実行に非定型SQL ツール(SQL*Plusなど)を使用し、システム内のロック待機中のセッション、およびそれに対応するブロッキング・ロックを出力します。このスクリプト・ファイルの位置は、オペレーティング・システムによって異なります。(UTLLOCKT.SQLを使用する前に、CATBLOCK.SQLスクリプトを実行する必要があります。) 

シリアライズ可能トランザクションを使用した同時実行性の制御

Oracle Databaseは、デフォルトでは、同時に実行されるトランザクションの同じ表および同じデータ・ブロック内での行の修正、追加または削除を許可しています。あるトランザクションによって行われた変更は、その変更を行ったトランザクションがコミットされるまで、別の同時トランザクションでは参照できません。

トランザクションAが、(DML文またはSELECT... FOR UPDATE文を使用して)別のトランザクションBによってロックされている行を更新または削除しようとすると、トランザクションAのDMLコマンドは、トランザクションBがコミットまたはロールバックされるまでブロックされます。トランザクションBがコミットされると、トランザクションAは、トランザクションBがそのデータベースに対して行った変更を参照できます。

この同時実行性モデルはほとんどのアプリケーションに適しています。これは、より高度な同時実行性が提供されて、パフォーマンスが改善されるためです。ただし、まれにシリアライズ可能なトランザクションが必要な場合もあります。シリアライズ可能トランザクションは、同時にではなく、一度に1トランザクションずつ(シリアルで)実行しているように見える方法で実行する必要があります。シリアル・モードで実行中の同時トランザクションでは、それらのトランザクションが1つずつ順次実行された場合に可能となるデータベースの変更のみが可能です。

図2-1は、シリアライズ可能トランザクション(B)と、別のトランザクション(A)との相互作用を示しています。

ANSI/ISO SQL規格SQL92は、考えられる3種類のトランザクションの相互作用、およびそれらの相互作用に対する保護を強化する4レベルの分離を定義しています。表2-4に、これらの相互作用および分離レベルの概要を示します。

表 2-4    ANSI分離レベルの概要 
分離レベル  内容を保証しない読込み1  反復不能な読込み2  仮読込み3 

READ UNCOMMITTED 

可能性あり 

可能性あり 

可能性あり 

READ COMMITTED 

可能性なし 

可能性あり 

可能性あり 

REPEATABLE READ 

可能性なし 

可能性なし 

可能性あり 

SERIALIZABLE 

可能性なし 

可能性なし 

可能性なし 

1 トランザクションは、別のトランザクションで変更されたコミットされていないデータを読み込むことができます。
2 トランザクションは、別のトランザクションでコミットされたデータを再度読み込み、その新しいデータを参照します。
3 トランザクションは問合せを再実行し、コミットされた別のトランザクションによって挿入された新しい行を検出できます。

これらの分離レベルに関するOracle Databaseの動作について、表2-5に概要を示します。

表 2-5    ANSI分離レベルとOracle Database 
分離レベル  説明 

READ UNCOMMITTED 

Oracle Databaseでは「内容を保証しない読込み」は許可されません。他のデータベース製品の中には、スループットの改善のために、この方法を使用するものもありますが、スループットの高いOracle Databaseでは不要です。 

READ COMMITTED 

Oracle Databaseは、READ COMMITTED分離標準に準拠しています。これは、すべてのOracle Databaseアプリケーションのデフォルト・モードです。Oracle Databaseでは、問合せの始め(スナップショット時)にコミット済のデータのみを参照するため、READ COMMITTED分離について実際にANSI/ISO SQL92規格で要求される以上の整合性を提供します。 

REPEATABLE READ 

通常、Oracle Databaseは、シリアライズ可能トランザクションSERIALIZABLEによって提供されるもの以外は、この分離レベルをサポートしていません。 

SERIALIZABLE 

通常、Oracle Databaseは、シリアライズ可能トランザクションSERIALIZABLEによって提供されるもの以外は、この分離レベルをサポートしていません。 

シリアライズ可能トランザクションの相互作用

図2-1に、シリアライズ可能トランザクション(トランザクションB)と、別のトランザクション(トランザクションA、シリアライズ可能またはコミット読込みのいずれか)との相互作用を示しています。

シリアライズ可能トランザクションが「ORA-08177: このトランザクションのアクセスをシリアル化できません」のエラーで失敗したとき、アプリケーションは次のいずれかで対処できます。

Oracle Databaseでは、同時トランザクションによるアクセスを管理するために、各データ・ブロックに制御情報を格納します。SERIALIZABLE分離レベルを使用するには、CREATE TABLEコマンドまたはALTER TABLEコマンドのINITRANS句を使用して、この制御情報の格納を取り消す必要があります。SERIALIZABLEモードを使用するには、INITRANSを3以上に設定する必要があります。

図 2-1    2つのトランザクションの時系列的働き


画像の説明

トランザクションの分離レベルの設定

トランザクションの分離レベルは、SET TRANSACTIONコマンドのISOLATION LEVEL句を使用して変更できます。SET TRANSACTIONコマンドは、トランザクションで最初に発行されるコマンドである必要があります。

トランザクション分離レベルをセッション全体に設定するには、ALTER SESSIONコマンドを使用します。

関連項目

SET TRANSACTIONコマンドおよびALTER SESSIONコマンドの構文の詳細は、『Oracle Databaseリファレンス』を参照してください。 

INITRANSパラメータ

Oracle Databaseでは、同時トランザクションによるアクセスを管理するために、各データ・ブロックに制御情報を格納します。したがって、トランザクション分離レベルをSERIALIZABLEに設定する場合は、ALTER TABLEコマンドを使用して、INITRANSを3以上に設定する必要があります。このパラメータを使用すると、Oracle Databaseは、ブロックにアクセスした最新トランザクションの履歴を記録するために十分な記憶域を、それぞれのブロック内に割り当てます。同じブロックを更新するトランザクションの数が多い表には、さらに大きい値を使用する必要があります。

参照整合性およびシリアライズ可能トランザクション

Oracle Databaseは、シリアライズ可能トランザクション内であっても読込みロックを使用しないため、あるトランザクションによって読み込まれたデータは、別のトランザクションでオーバーライドできます。アプリケーション・レベルでデータベースの整合性チェックを実行するトランザクションでは、読み込んだデータはトランザクション実行中には変更されないと考えないでください(そのような変更がトランザクションからはわからない場合も)。シリアライズ可能トランザクションを使用した場合でも、アプリケーション・レベルの整合性チェックのコードを十分注意して作成しないと、データベースの不整合が発生する可能性があります。ただし、この項に示されている例は、コミット読込みトランザクションおよびシリアライズ可能トランザクションの両方に該当するため注意してください。

図2-2に、2つの表の間の参照整合性の親子関係を保持するために、アプリケーション・レベルでチェックを実行する異なる2つのトランザクションを示します。一方のトランザクションは、親表に特定の主キー値を持つ行が存在するかどうかをチェックした後、対応する子である行を挿入します。もう一方のトランザクションは、対応するディテール行が存在しないことをチェックした後、親である行を削除します。この場合、両方のトランザクションが読み込んだデータは、そのトランザクションが完了する前には変更されないものと想定しています(確認はしません)。

図 2-2    参照整合性チェック


画像の説明

トランザクションAが実行した読込みのために、トランザクションBが親である行を削除できなくなることはありません。同様に、トランザクションBが子である行の問合せを行っても、トランザクションAが子である行を挿入できなくなることもありません。したがって、この使用例では、対応する親である行を持たない子である行がデータベースに残ります。どちらのトランザクションも、整合性チェックのため読み込んだデータに対する変更を他方が防げないため、両方のトランザクションがシリアライズ可能トランザクションであっても、このような不整合が発生する可能性があります。

この例に示されているとおり、一方のトランザクションで読み込まれたデータがもう一方のトランザクションで同時に書き込まれないように、処置を行う必要がある場合があります。これには、SQL92 SERIALIZABLEモードで定義されているトランザクション分離レベルよりもかなり高いレベルが必要です。

SELECT FOR UPDATEの使用

Oracle Databaseでは、前述の矛盾を簡単に防ぐことができます。

Oracle Databaseでは、トランザクションAの場合のような独立した問合せのかわりに、データベース・トリガーを使用して参照整合性を施行することもできます。たとえば、子表へのINSERTによって、BEFORE INSERT行レベル・トリガーを起動して、対応する親である行の有無をチェックできます。このトリガーは、SELECT FOR UPDATEを使用して親表を問い合せ、子である行を挿入するトランザクションの処理中に、親である行が(存在する場合)データベース内に残るようにします。対応する親である行が存在しない場合、トリガーは子である行の挿入を拒否します。

データベース・トリガーによって発行されたSQL文は、そのトリガーを起動したSQL文のコンテキスト内で実行されます。1つのトリガー内で実行されるすべてのSQL文は、トリガー起動文から参照する状態と同じデータベース状態を参照します。そのため、コミット読込みトランザクションでは、トリガー内のSQL文は、トリガー文の実行開始時点のデータベースを参照し、SERIALIZABLEモードで実行するトランザクションでは、SQL文は、そのトランザクションの開始時点のデータベースを参照します。いずれの場合も、トリガーでSELECT FOR UPDATEを使用すると、参照整合性が正しく施行されます。

READ COMMITTED分離およびSERIALIZABLE分離

Oracle Databaseの場合、アプリケーション開発者は異なる特性を持つ2つのトランザクション分離レベルのうちの1つを選択できます。READ COMMITTEDおよびSERIALIZABLE分離レベルは、どちらも高度な一貫性および同時実行性を提供します。これら2つの分離レベルは競合を軽減し、実社会でのアプリケーション配置用に設計されています。この項の後半では、2つの分離レベルを比較し、その選択の際に有効な情報を示します。

トランザクション集合の整合性

Oracle DatabaseのREAD COMMITTEDおよびSERIALIZABLE分離レベルについて説明するには、次のことを考慮すると効果的です。

どの読込みにおいても、同じコミット済トランザクション集合によって書き込まれたデータが戻される操作(問合せまたはトランザクション)を、「トランザクション集合整合である」といいます。トランザクション集合整合でない操作では、ある集合のトランザクションの変更が反映される読込みと、他のトランザクションによって行われた変更が反映される読込みが存在します。そのような操作では、そのデータベースは、コミットされたトランザクション集合が反映されていない状態のデータベースのように見えます。

Oracle DatabaseのREAD COMMITTEDモードでは、問合せによって読み込まれたすべての行が、その問合せが始まる前にコミットされているため、文単位でのトランザクション集合整合です。

Oracle DatabaseのSERIALIZABLEモードでは、シリアライズ可能トランザクション内のすべての文が、トランザクション開始時点のデータベースのイメージに対して実行されるため、トランザクション単位でのトランザクション集合整合です。

他のデータベース・システムでは、READ COMMITTEDモードで問合せを1回実行すると、トランザクション集合の整合性は失われます。この問合せでは、別のトランザクションによって行われた変更のサブセット以外見えないため、トランザクション集合は整合していません。たとえば、ディテール表とマスター表を結合すると、別のトランザクションによって挿入されたマスター・レコードを見ることはできますが、そのトランザクションによって挿入された対応するディテールは見えません(その逆も同じです)。READ COMMITTEDモードではこのような問題は回避されるため、読込みロック・システムより高い整合性が得られます。

読込みロック・システムでは、同時更新ができないようにするかわりに、SQL92 REPEATABLE READ分離によって、トランザクション・レベルではなく、文レベルでトランザクション集合の整合性が提供されます。仮(phantom)の保護がないということは、同一のトランザクションによって発行された2つの問合せが、他のトランザクションの別の集合によってコミットされたデータを参照できることを意味します。これらのシステムでは、スループットに制限がありデッドロックされやすいSERIALIZABLEモードの場合のみ、トランザクション・レベルでのトランザクション集合の整合性が提供されます。

コミット読込みトランザクションとシリアライズ可能トランザクションの比較

表2-6に、コミット読込みトランザクションとシリアライズ可能トランザクションとの間の主な類似点および相違点を説明します。

表 2-6    コミット読込みトランザクションとシリアライズ可能トランザクション 
操作  コミット読込み  シリアライズ可能 

内容を保証しない書込み 

可能性なし 

可能性なし 

内容を保証しない読込み 

可能性なし 

可能性なし 

反復不能な読込み 

可能性あり 

可能性なし 

仮読込み 

可能性あり 

可能性なし 

ANSI/ISO SQL 92への準拠 

あり 

あり 

スナップショット読込み時間 

文 

トランザクション 

トランザクション集合の整合性 

文レベル 

トランザクション・レベル 

行レベル・ロック 

あり 

あり 

読込みが書込みをブロック 

なし 

なし 

書込みが読込みをブロック 

なし 

なし 

異なる行の書込みが書込みをブロック 

なし 

なし 

同じ行の書込みが書込みをブロック 

あり 

あり 

阻止しているトランザクションの待機 

あり 

あり 

エラー「このトランザクションのアクセスをシリアル化できません」の発生する可能性 

なし 

あり 

阻止しているトランザクションの異常終了後のエラー 

なし 

なし 

阻止しているトランザクションのコミット後のエラー 

なし 

あり 

トランザクションの分離レベルの選択

それぞれのアプリケーションおよび作業負荷に適した分離レベルを選択する必要があります。また、異なるトランザクションにはそれぞれ個別の分離レベルを選択できます。分離レベルは、パフォーマンスと整合性のニーズ、およびアプリケーション・コーディング要件を考慮して選択します。

多数のユーザーが、トランザクションを同時に次々に送る環境の場合、予期されるトランザクション到着頻度および応答時間要件に対するトランザクション・パフォーマンスを評価して、十分なパフォーマンスを確保しながら必要な整合性を提供する分離レベルを選択する必要があります。多くの場合、高パフォーマンス環境では、整合性と同時実行性(トランザクションのスループット)を考慮して妥協点を見つける必要があります。

どちらのOracle Database分離モードも、行レベル・ロックとOracle Databaseの複数バージョン同時実行処理制御システムとを組み合せることによって、高レベルの整合性および同時実行性(およびパフォーマンス)を提供します。Oracle Databaseでは読込みと書込みの相互干渉がないため、問合せで整合性のあるデータが参照できる一方、READ COMMITTED分離およびSERIALIZABLE分離により、コミットされていない(内容が保証されない)データの読込みを防止し高レベルの同時実行性を提供することで、高いパフォーマンスを実現しています。

READ COMMITTED分離レベルでは、一部のトランザクションについては(仮読込みおよび反復不能な読込みのため)一貫性のない結果が生成される可能性は多少高くなりますが、かなり高い同時実行性を提供できます。SERIALIZABLE分離レベルの場合は、仮読込みおよび反復不能な読込みから保護されているため、より高い整合性が提供され、読込み/書込みトランザクションが問合せを2回以上実行する場合にはこの分離レベルは重要です。ただし、SERIALIZABLEモードでは、アプリケーションが「このトランザクションのアクセスをシリアル化できません」というエラーの有無を確認する必要があり、多数の同時トランザクションが更新のために同じデータにアクセスする環境では、スループットはかなり低下する可能性があります。データベースの整合性を確認するアプリケーション・ロジックでは、いずれのモードでも読込みが書込みをブロックしないように設定する必要があります。

トランザクションのためのアプリケーションのヒント

トランザクションをSERIALIZABLEモードで実行する場合、シリアライズ可能トランザクションの開始以降に、別のトランザクションにより変更されたデータを変更しようとすると、次のようなエラーが発生します。

ORA-08177: このトランザクションのアクセスをシリアル化できません

このエラーが発生した場合は、現行のトランザクションをロールバックし、操作を再実行します。トランザクションが新しいトランザクション・スナップショットを取得するため、操作が成功する可能性が高くなります。

トランザクションのロールバックおよび再実行によるパフォーマンスのオーバーヘッドを最小化するには、他の同時トランザクションと競合する可能性のあるDML文は、できるだけトランザクションの始めの方に置くようにしてください。

自律型トランザクション

この項では、自律型トランザクション(AT)の概要およびこのトランザクションの機能を簡単に説明します。

関連項目

自律型トランザクションの詳細は、『PL/SQLユーザーズ・ガイドおよびリファレンス』および第9章「トリガーのコーディング」を参照してください。 

プライマリ・トランザクションの最終結果とは関係なく、表に対して別の変更をコミットまたはロールバックすることが必要になる場合があります。たとえば、株式売買トランザクションでは、全体的な株式売買行為が実際に遂行されるかどうかに関係なく、顧客情報のコミットが必要な場合があります。またはそのトランザクションを実行中にトランザクション全体がロールバックされた場合でも、エラー・メッセージをデバッグ表にログする必要がある場合もあります。自律型トランザクションを使用すると、これらのタスクを実行できます。

自律型トランザクション(AT)は、別のトランザクション(メイン・トランザクション(MT))によって開始される独立したトランザクションです。自律型トランザクションを使用すると、メイン・トランザクションを停止して、SQL操作を実行し、そのSQL操作をコミットまたはロールバックした後でメイン・トランザクションを再開できます。

自律型トランザクションは、自律型スコープ内で実行されます。自律型スコープとは、プラグマ(コンパイラ・ディレクティブ)AUTONOMOUS_TRANSACTIONでマークされたルーチンです。このプラグマは、PL/SQLコンパイラに対して、ルーチンを自律型(非依存)としてマークするように指示します。ここで意味するルーチンには、次のものが含まれます。

図2-3に、メイン・ルーチン(MT)と自律型ルーチン(AT)との間の制御フローを示します。図からわかるように、自律型ルーチンでは、制御がメイン・ルーチンに戻る前に複数のトランザクション(AT1およびAT2)をコミットできます。

図 2-3    トランザクション制御フロー


画像の説明

自律型ルーチンの実行可能セクションに入ると、メイン・ルーチンが停止します。自律型ルーチンを終了すると、メイン・ルーチンが再開します。

COMMITおよびROLLBACKによって、アクティブな自律型トランザクションは終了しますが、自律型ルーチンは終了しません。図2-3に示すとおり、1つのトランザクションが終了すると、次のSQL文が別のトランザクションを開始します。

自律型トランザクションの特長をさらにいくつか示します。

図2-4に、自律型トランザクションが従う実行順序の例を示します。

図 2-4    自律型トランザクションの実行順序の例


画像の説明

自律型トランザクションの例

この項の2つの例では、自律型トランザクションの使用方法をいくつか説明します。

例に示すとおり、自律型トランザクションおよびメイン・トランザクションを使用する場合は、4種類の結果が考えられます。表2-7にこの結果を示します。表からわかるように、自律型トランザクションの結果とメイン・トランザクションの結果との間に依存性はありません。

表 2-7    トランザクションの結果 
自律型トランザクション  メイン・トランザクション 

コミット 

コミット 

コミット 

ロールバック 

ロールバック 

コミット 

ロールバック 

ロールバック 

購入注文の入力

図2-5に示すように、この例では、顧客が購入注文を入力します。購買契約が成立しなくても、その顧客の情報(名前、住所、電話番号など)は顧客情報表にコミットされます。

図 2-5    例: 購買指示


画像の説明

例: 預金払戻しの実行

この例では、顧客は口座から払戻しを実行しようとします。この処理で、メイン・トランザクションは2つの自律型トランザクション・スコープ(ATスコープ1およびATスコープ2)のいずれかをコールします。

次の図には、このトランザクションで考えられる使用例を3つ示します。

使用例1

払戻しに十分な預金残高があり、銀行が払戻しに応じます。これについては、図2-6に示してあります。

図 2-6    例: 預金払戻し−十分な預金残高


画像の説明

使用例2

払戻しに十分な預金残高はありませんが、この顧客には貸越し保護があります。したがって、銀行は払戻しに応じます。これについては、図2-7に示してあります。

図 2-7    例: 預金払戻し−不十分な預金残高で貸越し保護あり


画像の説明

使用例3

払戻しに十分な預金残高はなく、この顧客には貸越し保護もありません。したがって、銀行は払戻しを差し止めます。これについては、図2-8に示してあります。

図 2-8    例: 預金払戻し−不十分な預金残高で貸越し保護なし


画像の説明

自律型トランザクションの定義


注意

この項は、自律型トランザクションに対する一般的な理解を深める目的で提供されています。自律型トランザクションの詳細は、『PL/SQLユーザーズ・ガイドおよびリファレンス』を参照してください。 


自律型トランザクションを定義するには、プラグマ(コンパイラ・ディレクティブ)AUTONOMOUS_TRANSACTIONを使用します。このプラグマは、PL/SQLコンパイラに対して、プロシージャ、ファンクションまたはPL/SQLブロックを自律型(非依存)としてマークするように指示します。

このプラグマは、プロシージャ、ファンクションまたはPL/SQLブロックの宣言セクション内のどこにでも作成できます。ただし、コードを読みやすくするために、プラグマはセクションの一番上に作成するようにします。構文は次のとおりです。

PRAGMA AUTONOMOUS_TRANSACTION;

次の例では、パッケージ・ファンクションを自律型としてマークします。

CREATE OR REPLACE PACKAGE Banking AS
    FUNCTION Balance (Acct_id INTEGER) RETURN REAL;
    -- add 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
       --add appropriate code
    END;
    -- add additional functions and packages...
END Banking;

自律型トランザクションの制限事項

自律型トランザクションには、次の制限があることに注意してください。

記憶域エラー状態の後の実行の再開

長時間にわたって実行されるトランザクションが領域不足エラー状態によって中断されたときに、アプリケーションによって問題が発生した文を一時停止し、領域問題が修正された後でその文を再開することが可能です。この機能を、再開可能記憶域割当てといいます。この機能によって、時間がかかるロールバックを回避できます。また、操作を小さく分割したり、処理過程を追跡するコードを作成する必要がなくなります。

関連項目

  • 『Oracle Database概要』

  • 『Oracle Database管理者ガイド』

 

エラー状態の後に再開可能な操作

問合せ、DML操作および特定のDDL操作は、領域不足エラーが発生した場合、すべて再開可能です。この機能は、操作がSQL文によって直接実行されているか、または、ストアド・プロシージャ、無名PL/SQLブロック、SQL*Loader、OCIStmtExecute()などのOCIコール内で実行されている場合に適用されます。

操作は、次のようなエラーの後で再開可能です。

エラー状態の後の操作再開における制限

前述の方法では処理できない記憶域エラーもあります。ディクショナリ管理された表領域では、ロールバック・セグメントの上限に達するか、または索引または表の作成中にエクステントの最大数に達した場合、操作を再開できません。前述の方法にローカル管理表領域および自動UNDO管理を組み合せて使用してください。

一時停止された記憶域割当てを処理するアプリケーションの作成

操作が一時停止された場合、アプリケーションは通常のエラー・コードを受信しません。かわりに、AFTER SUSPENDイベントを検出しDBMS_RESUMABLEパッケージのファンクションをコールして問題についての情報を取得するトリガーをコーディングして、ロギングまたは通知を実行します。このパッケージを使用すると、次のことが可能です。

トリガーの本体内では、通知を実行できます。たとえば、オペレータにメール・メッセージを送り、領域問題について警告できます。

また、DBAが、DBA_RESUMABLEUSER_RESUMABLEおよびV$_SESSION_WAITデータ・ディクショナリ・ビューを使用して、一時停止された文を定期的に確認することもできます。

領域状態が(通常DBAによって)修正されると、一時停止された文は自動的に実行を再開します。タイムアウト周期が終了するまでに領域状態が修正されなかった場合は、その操作によってSERVERERROR例外が発生します。

トリガー自体の中で領域不足エラーが発生する可能性を減らすには、トリガーを自律型トランザクションとして宣言し、トリガーがSYSTEM表領域内のロールバック・セグメントを使用するようにする必要があります。一時停止された文が保持するロックによってトリガーにデッドロック状態が発生した場合、そのトリガーは強制終了され、アプリケーションは一時停止が発生しなかった場合の本来のエラー状態を受信します。トリガーによって領域不足状態が発生した場合、そのトリガーおよび一時停止された文はロールバックされます。トリガー内の例外ハンドラを介してロールバックを回避し、文が再開されるまで待つこともできます。

関連項目

DBA_RESUMABLEUSER_RESUMABLEおよびV$_SESSION_WAITデータ・ディクショナリ・ビューに関する詳細は、『Oracle Databaseリファレンス』を参照してください。 

再開可能記憶域割当ての例

次に示すトリガーは、データベース内の適用可能な記憶域エラーを処理します。いくつかのエラーでは、このトリガーは文を強制終了し、エラーに関する警告をメール・メッセージによってDBAに通知します。他の一時的なエラーでは、8時間以内に記憶域の問題が解決していることを想定して、8時間後に文を再開するように指定しています。

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 sys.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 := 'Subject: 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;


戻る 次へ
Oracle
Copyright © 2006 Oracle Corporation.

All Rights Reserved.
目次
目次
索引
索引