データの同時実行性と整合性

このページのスクリプト・コンテンツはナビゲーションのみを目的としており、いかなる方法においても内容を変更するものではありません。

この章では、マルチユーザー・データベース環境におけるOracle AI Databaseでどのようにデータ整合性が維持されるかについて説明します。

データの同時実行性と整合性の概要

シングル・ユーザーのデータベースでは、他のユーザーが同時に同じデータを変更することがないように、ユーザーはデータを変更できます。ただし、マルチユーザー・データベースでは、複数のトランザクション内の文によって、同じデータが同時に更新される可能性があります。同時に実行される複数のトランザクションでは、意味のある一貫した結果を出すことが必要です。

マルチユーザー・データベースには次の機能が備わっている必要があります。

トランザクションの同時実行における一貫したトランザクション動作を説明するために、データベース調査者は、シリアライズ可能性と呼ばれるトランザクション分離モデルを定義しています。シリアライズ可能トランザクションは、他のユーザーがデータベースのデータを変更していないように見える環境内で動作します。

一般に、この程度までのトランザクションの分離が望ましいとされますが、シリアライズ可能モードで数多くのアプリケーションを実行すると、アプリケーションのスループットがかなり低下する可能性があります。同時に実行される各トランザクションの完全な分離とは、あるトランザクションが別のトランザクションによって問合せされている表への挿入を実行できないという状態を指します。つまり、現実には、トランザクションの完全な分離とパフォーマンスとの間の妥協点を考慮する必要があります。

Oracle AI Databaseでは、マルチバージョン一貫性モデルや様々なタイプのロックおよびトランザクションを使用することによって、データ整合性が維持されます。これにより、データベースが複数の同時ユーザーに対するデータのビューを提示する場合、それぞれ特定の時点において一貫性があるビューにすることができます。異なるバージョンのデータ・ブロックを同時に存在する場合があるため、トランザクションでは問合せに要求された時点でコミットされたデータのバージョンが読み取られ、あるある特定の時点において一貫性のある結果が戻されます。

マルチバージョン読取り一貫性

Oracle AI Databaseでは、マルチバージョン機能によって、複数のバージョンのデータ が同時にマテリアライズされます。Oracle AI Databaseは、マルチバージョン読取り一貫性を維持します。

Oracleデータベースの問合せには、次の特性があります。

文レベルの読取り一貫性

Oracle AI Databaseでは、文レベルの読取り一貫性を常に適用することで、1つの問合せによって戻されたデータがコミット済で、ある特定の時点で一貫していることを保証します。

単一のSQL文の一貫性が保たれる基準となる時点は、トランザクション分離レベルおよび問合せの内容に応じて異なります。

関連項目:フラッシュバック問合せについて学習するには、『Oracle AI Database開発ガイド』を参照してください。

トランザクション・レベルの読取り一貫性

Oracle AI Databaseは、1つのトランザクションのすべての問合せに対して、トランザクション・レベルの読取り一貫性と呼ばれます読取り一貫性を実現することもできます。

この場合、トランザクション内の各文には、同じ時点のデータが表示されます。これは、トランザクション開始時点です。

シリアライズ可能トランザクションによる問合せでは、そのトランザクション自体が変更したデータも参照できます。たとえば、employeesを更新し、employeesを問い合せたトランザクションには、その更新内容が反映されます。トランザクション・レベルの読取り一貫性によってリピータブル・リードが実現され、問合せで仮読取りが検索されなくなります。

読取り一貫性とUNDOセグメント

マルチバージョン読取り一貫性モデルを管理するには、表が同時に問合せおよび更新された場合に、読取り一貫性のある一連のデータがデータベースで作成される必要があります。

Oracle AI Databaseは、UNDOデータを使用して読取り一貫性を実現しています。

ユーザーがデータを変更すると、常にOracle AI DatabaseによってUNDOエントリが作成されます。UNDOエントリはUNDOセグメントに書き込まれます。UNDOセグメントには、未コミットのトランザクションや、最近コミットされたトランザクションによって変更されたデータの古い値が含まれています。このため、同じデータの異なる時点の複数のバージョンがデータベース内に存在することになります。データの読取り一貫性ビューを提供し、非ブロック化問合せを可能にするために、データベースでは異なる時点のデータのスナップショットを使用できます。

読取り一貫性は、単一のインスタンス内、およびOracle Real Application Clusters(Oracle RAC)環境内で保証されています。Oracle RACでは、データ・ブロックの読取り一貫性イメージをデータベース・インスタンス間で転送するために、キャッシュ・フュージョンと呼ばれるキャッシュ間ブロック転送メカニズムを使用します。

関連情報:

読取り一貫性: 例

この例は、コミット読取り分離レベルで、UNDOデータを使用して文レベルの読取り一貫性を提供する問合せの例を示しています。

図1: コミット読取り分離レベルでの読取り一貫性

画像cncpt069.gifの説明

問合せによってデータ・ブロックを取得する場合、データベースによって、各ブロックのデータが問合せ開始時のブロックの内容を反映したものになることが保証されます。必要に応じて、ブロックに対する変更がロールバックされ、ブロックが問合せ処理の開始時点の内容に再構成されます。

データベースでは、SCNと呼ばれる内部順序付けメカニズムを使用することで、トランザクションの順序が保証されます。SELECT文が実行フェーズに移行すると、データベースによって、問合せの実行開始時点で記録されたSCNが特定されます。図12-1では、このSCNは10023です。問合せでは、SCN 10023に対応したコミット済データが戻されます。

図12-1では、10023より後のSCNを持つブロック(SCN 10024の2つのブロック)は変更済データであることが示されています。この場合、SELECT文では、コミット済の変更と一貫性があるバージョンのブロックが必要となります。データベースでは、現在のデータ・ブロックが新しいバッファにコピーされ、前のバージョンのブロックを再構築するためにUNDOデータが適用されます。このように再構築されたデータ・ブロックは、読取り一貫性(CR)クローンと呼ばれます。

図12-1では、データベースによって2つのCRクローンが作成されており、1つのブロックではSCN 10006との一貫性が保たれ、もう1つのブロックではSCN 10021との一貫性が保たれています。問合せに対しては、この再構築されたデータが戻されます。Oracle AI Databaseでは、このようにして内容を保証しない読取りが回避されています。

関連項目: 「データベース・バッファ・キャッシュ」および「システム変更番号(SCN)」

読取り一貫性とInterested Transaction List

各セグメント・ブロックのブロック・ヘッダーにinterested Transaction List (ITL)が含まれています。

データベースではITLを使用して、ブロックの変更が開始された時点でトランザクションがコミットされているかどうかが判断されます。

ITLのエントリは、ロックされた行のあるトランザクション、およびブロック内のコミット済の変更や未コミットの変更を含む行を表しています。ITLは、データベースに対する変更が行われたタイミングの情報を提供するUNDOセグメント内のトランザクション表を指しています。

ある意味では、ブロック・ヘッダーには、ブロック内の各行に影響を与えたトランザクションの最新の履歴が含まれていると考えられます。CREATE TABLE文およびALTER TABLE文のINITRANSパラメータは、保持するトランザクション履歴の量を制御します。

関連項目: INITRANSパラメータについて学習するには、Oracle AI Database SQL言語リファレンスを参照してください。

読取り一貫性および遅延挿入

遅延挿入という特殊な種類の挿入で、標準の読取り一貫性メカニズムは使用されません。

遅延挿入では、MEMOPTIMIZE_WRITEヒントを使用して、MEMOPTIMIZE FOR WRITEとして指定された表に挿入します。データベースではこれらの挿入を、バッファ・キャッシュではなくラージ・プールでバッファします。データベースでは、REDOおよびUNDOを使用して変更を追跡することはありません。かわりに、領域管理コーディネータ(SMCO)によってバッファがディスクに書き込まれると、データベースによって変更が自動的にコミットされます。この変更はロールバックできません。

遅延挿入は、次の重要な点で従来の挿入とは異なります。

データ消失を回避する必要があるクライアント・アプリケーションでは、ラージ・プールへの書込み後にデータのローカル・コピーを保持する必要があります。クライアントはDBMS_MEMOPTIMIZEパッケージを使用してメモリーへの書込みの永続性を追跡し、DBMS_MEMOPTIMIZE_ADMINパッケージを使用してデータベースを強制的にディスクに書き込むことができます。

関連情報:

ロックのメカニズム

一般に、マルチユーザー・データベースでは、なんらかのデータ・ロックを使用してデータの同時実行性、一貫性、および整合性の問題を解決します。

ロックは、同じリソースにアクセスするトランザクション間で、破壊的な相互作用が出現しないようにするメカニズムです。

関連項目: 「Oracle AI Databaseのロック・メカニズムの概要」

ANSI/ISOトランザクション分離レベル

ANSIとISO/IECの両方で採用されているSQL規格では、トランザクション分離レベルが4つ定義されています。これらのレベルは、トランザクション処理のスループットに与える影響の度合いが異なります。

これらの分離レベルは、複数のトランザクションを同時に実行するときに防ぐ必要がある現象という観点から定義されています。回避可能な現象とは、次のものです。

SQL規格では、特定の分離レベルで実行されるトランザクションで起こり得ることという観点で4つの分離レベルを定義しています。表12-1に、これらのレベルを示します。

表1分離レベル別による回避可能な読取り現象

分離レベル ダーティ・リード 非リピータブル・リード 仮読取り
未コミットの読取り 可能 可能 可能
読取りがコミットされました 不可能 可能 可能
反復可能読取り 不可能 不可能 可能
シリアル化可能 不可能 不可能 不可能

Oracle AI Databaseには、コミット読取り(デフォルト)およびシリアライズ可能の分離レベルがあります。また、読取り専用モードも提供されています。

関連情報:

Oracle AI Databaseのトランザクション分離レベルの概要

トランザクション分離レベルのANSI規格は、各分離レベルで許可または防止される現象という観点から定義されています。

Oracle AI Databaseでは、トランザクション分離レベルが提供されています。

関連情報:

コミット読取り分離レベル

コミット読取り分離レベルで、トランザクションによって実行される問合せにおいて、トランザクション開始の前ではなく、問合せ終了前にコミット済のデータのみが表示されます。

この分離レベルがデフォルトになります。これはトランザクションの競合がほとんど発生しないデータベース環境に適しています。

コミット読取りトランザクション内の問合せでは、問合せ処理中にコミットされるデータは読み取られません。たとえば、100万行を持つ表の問合せ中に、別のトランザクションによって行950,000への更新がコミットされたとすると、この問合せで行950,000を読み取っても、その変更は反映されていません。ただし、問合せによって読み取られたデータを他のトランザクションに変更することはできないため、他のトランザクションは問合せ実行の間にデータが変更される可能性があります。このため、同じ問合せを2回実行するトランザクションでは、ファジー読取りと仮読取りが発生する可能性があります。

コミット読取り分離レベルでの読取り一貫性

データベースでは、ユーザーが何もしなくても、あらゆる問合せに対して一貫した結果セットが保証され、データ整合性が保証されます。

UPDATE文のWHERE句などで使用される暗黙的問合せでは、一貫した結果セットが保証されます。ただし、暗黙的問合せ内の各文では、そのDML文自体によって行われた変更は参照されず、変更前に存在したデータが参照されます。

SELECT文のリストにPL/SQLファンクションが含まれる場合、親SQLレベルではなくPL/SQLファンクション・コード内で実行されるSQL文のレベルにおいて、文レベルの読取り一貫性が適用されます。たとえば、ファンクションは、別のユーザーがデータを変更およびコミットした表にアクセスする場合があります。ファンクション内のSELECTの実行ごとに、読取り一貫性を備えた新しいスナップショットが設定されます。

関連項目: 「副問合せ」

コミット読取りトランザクション内での書込みの競合

コミット読取りトランザクションでは、トランザクションがコミットされていない同時トランザクションによって更新された行を変更しようとすると、競合する書込みが実行されます。

行の変更を防止するトランザクションは、ブロックしているトランザクションと呼ばれる場合があります。コミット読取りトランザクションは、ブロックしているトランザクションが終了して行ロックが解除されるまで待機します。

オプションは次のとおりです:

次の表に、トランザクション1 (シリアライズ可能トランザクションまたはコミット読取りトランザクション)とコミット読取りトランザクション2との間の相互作用を示します。これは、更新の消失と呼ばれるような典型的な状況を示しています。トランザクション1による更新内容は、トランザクション1がコミットしても表にはありません。このような更新内容の消失の問題をいかに回避するかは、アプリケーション開発の重要な点です。

表2 READ COMMITTEDトランザクションにおける書込みと更新内容が消失する

セッション 1 セッション 2 説明
SQL> SELECT last_name,
  salary FROM employees
  WHERE last_name IN
  ('Banda', 'Greene',
 'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 6200
 Greene 9500 
アクションはありません。 セッション1で、Banda、GreeneおよびHintzの給与を問い合せます。Hintzという名前の従業員が見つかりません。
SQL> UPDATE employees
  SET salary = 7000 WHERE
  last_name = 'Banda';
アクションはありません。 セッション1で、Bandaの給与を更新することによってトランザクションを開始します。トランザクション1のデフォルトの分離レベルは、READ COMMITTEDです。
アクションはありません。
SQL> SET TRANSACTION
  ISOLATION LEVEL
  READ COMMITTED;
セッション2でトランザクション2を開始して、分離レベルを明示的にREAD COMMITTEDに設定します。
アクションはありません。
SQL> SELECT last_name,
  salary FROM employees
  WHERE last_name IN
 ('Banda', 'Greene',
 'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 6200
 Greene 9500
トランザクション2で、Banda、GreeneおよびHintzの給与を問い合せます。Oracle AI Databaseでは読取り一貫性が使用され、トランザクション1によって行われた未コミットの更新前のBandaの給与を表示します。
アクションはありません。
SQL> UPDATE employees
  SET salary = 9900
  WHERE last_name='Greene';
トランザクション1ではBandaの行のみがロックされているため、トランザクション2でGreeneの給与が正常に更新されます。
SQL> INSERT INTO
  employees (employee_id,
  last_name, email,
  hire_date, job_id)
  VALUES (210, 'Hintz',
  'JHINTZ', SYSDATE,
  'SH_CLERK');
アクションはありません。 トランザクション1で、従業員Hintzの行を挿入しますが、コミットはしません。
アクションはありません。
SQL> SELECT last_name,
  salary FROM employees
  WHERE last_name IN
  ('Banda', 'Greene',
 'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 6200
 Greene 9900

トランザクション2で、従業員Banda、GreeneおよびHintzの給与を問い合せます。

トランザクション2では、このトランザクション自体で更新したGreeneの給与を参照できます。トランザクション2では、トランザクション1によって行われた未コミットのBandaの給与の更新やHintzの挿入は表示されません。

アクションはありません。
SQL> UPDATE employees SET
 salary = 6300 WHERE
  last_name = 'Banda';

  -- prompt does not return 
トランザクション2で、現在トランザクション1によってロックされているBandaの行の更新を試行したため、書込みの競合が発生します。トランザクション2は、トランザクション1の終了を待機します。
SQL> COMMIT;
アクションはありません。 トランザクション1では作業をコミットし、トランザクションを終了します。
アクションはありません。
1 row updated.

  SQL>
Bandaの行に対するロックが解除されたため、トランザクション2ではBandaの給与が更新されています。
アクションはありません。
SQL> SELECT last_name,
  salary FROM employees
  WHERE last_name IN
 ('Banda', 'Greene',
  'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 6300
 Greene 9900
 Hintz
トランザクション2で、従業員Banda、GreeneおよびHintzの給与を問い合せます。トランザクション1によってコミットされたHintzの挿入がトランザクション2でも参照可能になりました。トランザクション2では、このトランザクション自体で行ったBandaの給与への更新が表示されます。
アクションはありません。
COMMIT;
トランザクション2では作業をコミットし、トランザクションを終了します。
SQL> SELECT last_name,
  salary FROM employees
  WHERE last_name IN
  ('Banda', 'Greene',
 'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 6300
 Greene 9900
 Hintz
アクションはありません。 セッション1で、Banda、GreeneおよびHintzの行を問い合せます。Bandaの給与は6300ですが、これはトランザクション2で更新された値です。トランザクション1でBandaの給与を7000に更新しましたが、この更新内容は消失しました。

関連情報:

シリアライズ可能分離レベル

シリアライズ可能分離レベルでは、問合せの開始時ではなく、トランザクションの開始時にコミット済の変更およびこのトランザクション自体が行った変更のみを参照できる。

シリアライズ可能トランザクションは、他のユーザーがデータベースのデータを変更していないように見える環境内で動作します。シリアライズ可能な分離は、次のような環境に適しています。

シリアライズ可能分離では、通常は文レベルで確保される読取り一貫性が、トランザクション全体に拡張されます。トランザクションによって読み取られるすべての行は、再度読み取っても同じであることが保証されます。トランザクション実行中は、問合せによって戻される結果が同じであることが保証されるため、トランザクションの実行時間に関係なく、他のトランザクションによる変更は問合せで参照できません。シリアライズ可能トランザクションでは、内容を保証しない読取り、ファジー読取りまたは仮読取りの現象は発生しません。

Oracle AI Databaseの場合、シリアライズ可能なトランザクションでは、他のトランザクションで行が変更され、シリアライズ可能なトランザクションが開始されたときにすでにコミットされている行のみ変更できます。シリアライズ可能トランザクションが、その開始後にコミットされた別のトランザクションによって変更されたデータの更新または削除を試行すると、データベースでは次のようなエラーが生成されます。

ORA-08177: Cannot serialize access for this transaction

シリアライズ可能トランザクションでORA-08177エラーが発生した場合、アプリケーションでは次のいずれかのアクションを実行できます。

次の表に、シリアライズ可能トランザクションと他のトランザクションとの間の相互作用を示します。シリアライズ可能トランザクションにおいては、シリアライズ可能トランザクションの開始後に他のトランザクションでコミットされた行の変更を試行しなければ、シリアライズ・アクセスの問題を回避できます。

表3シリアライズ可能トランザクション

セッション 1 セッション 2 説明
SQL> SELECT last_name, salary FROM employees WHERE
  last_name IN ('Banda',
  'Greene', 'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 6200
 Greene 9500
アクションはありません。 セッション1で、Banda、GreeneおよびHintzの給与を問い合せます。Hintzという名前の従業員が見つかりません。
SQL> UPDATE employees
  SET salary = 7000
  WHERE last_name='Banda';
アクションはありません。 セッション1で、Bandaの給与を更新することによってトランザクション1を開始します。デフォルトの分離レベルはREAD COMMITTEDです。
アクションはありません。
SQL> SET TRANSACTION
  ISOLATION LEVEL SERIALIZABLE;
セッション2でトランザクション2を開始して、SERIALIZABLE分離レベルに設定します。
アクションはありません。
SQL> SELECT last_name, salary FROM employees
  WHERE last_name IN
  ('Banda', 'Greene', 'Hintz');

  LAST_NAME SALARY
 ------------ ----------
 Banda 6200
 Greene 9500
トランザクション2で、Banda、GreeneおよびHintzの給与を問い合せます。Oracle AI Databaseでは読取り一貫性が使用され、トランザクション1によって行われた未コミットの更新前のBandaの給与を表示します。
アクションはありません。
SQL> UPDATE employees
  SET salary = 9900
  WHERE last_name = 'Greene';
Bandaの行のみがロックされているため、トランザクション2でGreeneの給与は正常に更新されます。
SQL> INSERT INTO employees
  (employee_id, last_name,
  email, hire_date, job_id)
  VALUES (210, 'Hintz',
  'JHINTZ', SYSDATE,'SH_CLERK');
アクションはありません。 トランザクション1で、従業員Hintzの行を挿入します。
SQL> COMMIT;
アクションはありません。 トランザクション1では作業をコミットし、トランザクションを終了します。
SQL> SELECT last_name, salary
  FROM employees
  WHERE last_name IN
  ('Banda', 'Greene', 'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 7000
 Greene 9500
 Hintz
SQL> SELECT last_name, salary FROM employees
  WHERE last_name IN
 ('Banda', 'Greene', 'Hintz');

  LAST_NAME SALARY
 ------------- ---------
 Banda 6200
 Greene 9900

セッション1で従業員Banda、GreeneおよびHintzの給与を問い合せると、トランザクション1によってコミットされた変更が表示されます。セッション1では、トランザクション2での未コミットのGreeneの更新は参照できません。

トランザクション2で、従業員Banda、GreeneおよびHintzの給与を問い合せます。Oracle AI Databaseの読取り一貫性により、トランザクション1でコミットされたHintzの挿入およびBandaの更新は、トランザクション2では表示されない。トランザクション2では、このトランザクション自体で行ったGreeneの給与への更新が表示されます。

アクションはありません。
COMMIT;
トランザクション2では作業をコミットし、トランザクションを終了します。
SQL> SELECT last_name, salary
  FROM employees
  WHERE last_name IN
  ('Banda', 'Greene', 'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 7000
 Greene 9900
 Hintz
SQL> SELECT last_name, salary
 FROM employees
  WHERE last_name IN
  ('Banda', 'Greene', 'Hintz');

  LAST_NAME SALARY
 ------------- ---------
 Banda 7000
 Greene 9900
 Hintz
両方のセッションで、Banda、GreeneおよびHintzの給与を問い合せます。各セッションで、トランザクション1およびトランザクション2で行われたすべてのコミット済の変更を参照できます。
SQL> UPDATE employees
  SET salary = 7100
  WHERE last_name = 'Hintz';
アクションはありません。 セッション1で、Hintzの給与を更新することによってトランザクション3を開始します。トランザクション3のデフォルトの分離レベルは、READ COMMITTEDです。
アクションはありません。
SQL> SET TRANSACTION
  ISOLATION LEVEL SERIALIZABLE;
セッション2でトランザクション4を開始して、SERIALIZABLE分離レベルに設定します。
アクションはありません。
SQL> UPDATE employees
  SET salary = 7200
  WHERE last_name = 'Hintz';

  -- prompt does not return
トランザクション4で、Hintzの給与の更新を試みますが、トランザクション3でHintzの行がロックされているためにブロックされます。トランザクション4は、トランザクション3の後のキューに入ります。
SQL> COMMIT;
アクションはありません。 トランザクション3でHintzの給与の更新をコミットして、トランザクションを終了します。
アクションはありません。
UPDATE employees
  SET salary = 7200
  WHERE last_name = 'Hintz'
 *
 ERROR at line 1:
  ORA-08177: can't
  serialize access for
  this transaction
コミットしてトランザクション3を終了することによって、トランザクション4におけるHintzの更新がORA-08177エラーが発生して失敗します。この問題は、トランザクション3がトランザクション4が開始した後にヒント更新をコミットしたために発生します。
アクションはありません。
SQL> ROLLBACK;
セッション2で、トランザクション4をロールバックして終了します。
アクションはありません。
SQL> SET TRANSACTION
  ISOLATION LEVEL SERIALIZABLE;
セッション2でトランザクション5を開始して、SERIALIZABLE分離レベルに設定します。
アクションはありません。
SQL> SELECT last_name,
  salary FROM employees
  WHERE last_name IN
  ('Banda', 'Greene', 'Hintz');

  LAST_NAME SALARY
 ------------- ----------
 Banda 7000
 Greene 9900
 Hintz 7100
トランザクション5で、Banda、GreeneおよびHintzの給与を問い合せます。トランザクション3によってコミットされたHintzの給与の更新を参照できます。
アクションはありません。
SQL> UPDATE employees
  SET salary = 7200
  WHERE last_name='Hintz';

  1 row updated.

トランザクション5で、Hintzの給与を異なる値に更新します。トランザクション5が開始される前にトランザクション3でのHintzの更新をコミットしているため、シリアライズ・アクセスの問題は回避されます。

ノート: トランザクション5が開始された後に、別のトランザクションでHintzの行を更新してコミットした場合は、再度シリアライズ・アクセスの問題が発生します。

アクションはありません。
SQL> COMMIT; 
セッション2で、問題なく更新をコミットして、トランザクションを終了します。

関連情報:

読取り専用分離レベル

読取り専用分離レベルはシリアライズ可能分離レベルと類似していますが、読取り専用トランザクションでは、SYSユーザー以外はトランザクションでデータを変更できません。

読取り専用トランザクションでは、ORA-08177エラーは発生しません。読取り専用トランザクションは、トランザクション開始時点での一貫性を保たれる必要があるレポートの生成に役立ちます。

Oracle AI Databaseでは、必要に応じてUNDOセグメントからデータを再構築することによって、読取り一貫性を実現しています。UNDOセグメントは循環方式で使用されるため、データベースではUNDOデータを上書きできます。長時間実行されるレポートでは、読取り一貫性を保つために必要なUNDOデータが他のトランザクションによって再利用され、snapshot too oldというエラーが発生することがあります。UNDO保存期間とは、古いUNDOデータを上書きせずに保存する最低期間を設定することで、この問題を適切に回避します。

関連情報:

Oracle AI Databaseのロック・メカニズムの概要

ロックは破壊的な相互作用が起きないようにするメカニズムである。

共有データにアクセスする複数のトランザクション間で不正確なデータの更新または基礎となるデータ構造の不正な変更を引き起こす場合に、相互作用は破壊的になります。ロックは、データベースの同時実行性および一貫性を維持するために非常に重要です。

ロック動作の概要

データベースでは、ロックを取得する操作に応じて、複数のタイプのロックが使用されます。

一般に、データベースでは、排他ロックと共有ロックの2種類のロックが使用されます。排他ロックは、1つのリソース(行や表など)に対して1つのみ取得でき、共有ロックは、1つのリソースに対して複数取得できます。

ロックは、読取り側と書込み側の相互作用に影響を与えます。読取り側はリソースの問合せで、書込み側はリソースを変更する文です。次に、Oracle AI Databaseにおける、リーダーおよびライターに対するロック動作の概要を示します。

関連情報:

ロックの使用

シングル・ユーザーのデータベースでは、情報を変更するのは1人のユーザーのみであるため、ロックは必要ありません。ただし、複数のユーザーがデータにアクセスして変更する場合、データベースには、同じデータに対する同時変更を防止する手段が必要です。

ロックによって、次のようなデータベースの重要な要件を満たすことが可能になります:

Oracle AI Databaseでは、ロック・メカニズムを使用して、トランザクション間のデータの同時実行性、一貫性および整合性を確保します。ロックは自動的に実行されるため、ユーザーの操作は必要ありません。

ロックの必要性については、単一の行に対する同時更新で説明できます。次の例では、単純なWebベースのアプリケーションによって、エンド・ユーザーに対して従業員の電子メールおよび電話番号が表示されます。アプリケーションでは、次のようなUPDATE文を使用してデータが変更されます。

UPDATE employees
SET    email = ?, phone_number = ?
WHERE  employee_id = ?
AND    email = ?
AND    phone_number = ?

この例のUPDATE文では、WHERE句中の電子メールと電話番号は、特定の従業員に関する変更前の元の値になります。この更新では、アプリケーションで変更される行は、最後に読み取られ、ユーザーに表示された後、変更されていないことが保証されます。このようにして、アプリケーションでは、あるユーザーによって行われた変更を他のユーザーが上書きして更新内容が消失する、更新内容の消失の問題が回避されます(更新内容の消失の例は、表12-2を参照)。表12-4に、2つのセッションがほぼ同時にemployees表の同じ行の変更を試行した場合の一連のイベントを示します。

表4行ロックの例

T セッション 1 セッション 2 摘要
t0
SELECT employee_id as ID,
  email, phone_number
  FROM hr.employees
  WHERE last_name='Himuro';
ID EMAIL PHONE_NUMBER
 --- ------- ------------
 118 GHIMURO 515.127.4565
  セッション1で、hr1ユーザーがhr.employeesのHimuroのレコードを問い合せて、employee_id(118)、email(GHIMURO)およびphone_number(515.127.4565)属性を表示します。
t1  
SELECT employee_id as ID,
 email, phone_number
  FROM hr.employees
  WHERE last_name='Himuro';
ID EMAIL PHONE_NUMBER
 --- ------- ------------
 118 GHIMURO 515.127.4565
セッション2で、hr2ユーザーがhr.employeesのHimuroのレコードを問い合せて、employee_id(118)、email(GHIMURO)およびphone_number(515.127.4565)属性を表示します。
t2
UPDATE hr.employees SET
  phone_number='515.555.1234'
 WHERE employee_id=118
 AND email='GHIMURO'
 AND phone_number =
  '515.127.4565';

  1 row updated.
  セッション1で、hr1ユーザーがその行の電話番号を515.555.1234に更新します。この場合、GHIMUROの行に対してロックを取得します。
t3  
UPDATE hr.employees SET
  phone_number='515.555.1235'
 WHERE employee_id=118
 AND email='GHIMURO'
 AND phone_number =
  '515.127.4565';

  -- SQL*Plus does not show
 -- a row updated message or
 -- return the prompt.

セッション2で、hr2ユーザーが同じ行を更新しようとしますが、現在hr1が行を処理中のためブロックされます。

hr2による更新は、hr1による更新とほぼ同時に試行されました。

t4
COMMIT;

  Commit complete.
 

セッション1で、hr1ユーザーがトランザクションをコミットします。

このコミットによってHimuroに対する変更が確定され、待機しているセッション2のブロックが解除されます。

t5  
0 rows updated.

セッション2で、hr2ユーザーは、GHIMUROの行が変更されたため、条件に一致しなくなったことに気付きます。

条件が一致しないため、セッション2ではレコードが更新されません。

t6
UPDATE hr.employees SET
  phone_number='515.555.1235'
 WHERE employee_id=118
 AND email='GHIMURO' AND
  phone_number='515.555.1234';

  1 row updated.
  セッション1で、hr1ユーザーは、GHIMUROの行を誤った電話番号で更新したことに気付きます。そのためユーザーは新たにトランザクションを開始して、この行の電話番号を515.555.1235に更新します。これによりGHIMUROの行がロックされます。
t7  
SELECT employee_id as ID,
  email, phone_number
  FROM hr.employees
  WHERE last_name='Himuro';
ID EMAIL PHONE_NUMBER
 --- ------- ------------
 118 GHIMURO 515.555.1234
セッション2で、hr2ユーザーは、hr.employeesのHimuroのレコードを問い合せます。レコードには、t4でセッション1によってコミットされた電話番号の更新内容が表示されます。Oracle AI Databaseの読取り一貫性によって、セッション2ではt6の未コミットの変更は表示されません。
t8  
UPDATE hr.employees SET
  phone_number='515.555.1235
  WHERE employee_id=118
 AND email='GHIMURO'
 AND phone_number =
 '515.555.1234';

  -- SQL*Plus does not show
 -- a row updated message or
 -- return the prompt.
セッション2で、hr2ユーザーが同じ行を更新しようとしますが、現在hr1が行を処理中のためブロックされます。
t9
ROLLBACK;

  Rollback complete.
  セッション1で、hr1ユーザーがトランザクションをロールバックして終了します。
t10  
1 row updated.
セッション1による更新がロールバックされたため、セッション2による電話番号の更新は成功します。GHIMUROの行が条件に一致するため、更新は成功します。
t11  
COMMIT;

  Commit complete.
セッション2で、更新をコミットして、トランザクションを終了します。

Oracle AI Databaseでは、SQL文を実行するときに、必要なロックを自動的に取得します。たとえば、セッションによるデータの変更が許可される前に、最初にデータをロックする必要があります。ロックによってセッションは更新対象データに対する排他制御を取得するため、ロックが解除されるまでは他のトランザクションはロックされたデータを変更できません。

Oracle AI Databaseのロック・メカニズムはトランザクション制御と密接に結び付けられているため、アプリケーション設計者はトランザクションを適切に定義する必要があるのみで、ロックはOracle AI Databaseによって自動的に管理されます。ユーザーはリソースを明示的にロックする必要はありませんが、Oracle AI Databaseにはユーザーが手動でデータをロックするための方法も用意されています。

次の項では、Oracle AI Databaseでデータの同時実行性が実現される方法を理解するための重要な概念を説明します。

関連項目: 更新内容の消失防止に役立つサブプログラムを含むOWA_OPT_LOCKパッケージについて学習するには、Oracle AI Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンスを参照してください

ロックモード

Oracle AI Databaseでは、最高水準のデータ同時実行可能性を実現しながらフェイルセーフなデータの整合性を確保するために、可能な限り低い制限レベルが自動的に使用されます。

制限レベルが低いほど、他のユーザーによるデータへのアクセスがより容易になります。逆に、制限レベルが高いほど、他のトランザクションで取得できるロックのタイプがより制限されます。

Oracle AI Databaseでは、マルチユーザー・データベースで2つのロック・モードを使用します。

あるトランザクションで、SELECT ... FOR UPDATE文を使用して単一の表の行を選択するとします。このトランザクションでは、排他行ロックおよび行共有表ロックを取得します。行ロックでは、その他のセッションは、ロックされた行以外の任意の行を変更できますが、表ロックでは、セッションによる表の構造の変更が禁止されています。したがって、データベースでは、任意の数の文を実行できます。

ロック変換とロックの段階的拡大

Oracle AI Databaseでは、必要な場合にロック変換が実行されます。

ロックへの変換では、データベースによって、低い制限の表のロックが、より高い制限の1つに自動的に変換されます。たとえば、あるトランザクションで特定の従業員に対するSELECT ... FOR UPDATEを発行し、その後ロックされた行を更新すると仮定します。この場合、データベースでは、行共有表ロックが行排他表ロックに自動的に変換されます。トランザクションは、トランザクション内で挿入、更新または削除の対象になる行すべてに対して排他ロックを保持します。行ロックは、制限の最も高い程度で取得されるため、ロック変換はまったく必要なく、実行されません。

ロック変換は、あるレベル(行レベルなど)、1つのレベルで多数のロック解除が保持され、データベースがより高いレベルの粒度(表レベルなど)にランクを上げると発生する11とは異なります。あるセッションが表の中の多数の行をロックした場合、データベースによっては、行ロックが単一の表ロックに自動的に拡大される場合があります。ロックの数は少なくなりますが、ロックされている対象の制限は大きくなります。

Oracle AI Databaseでは、ロックがエスカレーションされることはありません。 ロックの段階的拡大はデッドロックの可能性を大幅に増します。たとえば、システムがトランザクション1のためにロックの拡大を試行しますが、トランザクション2によって保持されているロックのために拡大できないとします。トランザクション2の処理を続行するために同じデータのロックの段階的拡大が必要な場合、デッドロックが発生します。

時間のロック

Oracle AI Databaseでは、なんらかのイベントが発生すると、トランザクションがそのリソースを必要としなくなるように、ロックが自動的に解放されます。

通常、トランザクション内の文で取得したロックは、トランザクションの存続期間中保持されます。これらのロックは、同時トランザクションによって内容を保証しない読取り、更新の内容の消失、有害なDDLなどの損傷を招く干渉を防止します。ノート:索引付けされていない外部キーは、トランザクションではなく、文の存続期間中保持されるため、子表に対して実行される表ロック。また、DBMS_LOCKパッケージを使用すると、ユーザー定義のロックを自由に割当ておよび解除でき、トランザクションの境界を越えて保持することもできます。

Oracle AI Databaseでは、トランザクションをコミットまたはロールバックすると、そのトランザクション内の文で取得したすべてのロックが解除します。また、Oracle AI Databaseは、セーブポイントまでロールバックすると、セーブポイントより後で取得されたロックも解除します。ただし、ロックを解除されて使用可能となったリソースに対してロックを取得できるのは、ロック中だったリソースを待機していなかったトランザクションのみです。ロック中のリソースを待機していたトランザクションは、元のトランザクションが完全にコミットまたはロールバックされるまで待機し続けます。

関連情報:

ロックおよびデッドロック

デッドロックとは、2人以上のユーザーが、相手がロックされているデータをお互いに待機している状況を指すものです。デッドロックが発生すると、トランザクションは続行されません。

Oracle AI Databaseでは、デッドロックを自動的に検出し、デッドロックに関係している文の一方をロールバックし、競合する一連の行ロックを解放することにより、デッドブロックを自動で解決します。また、データベースでは、文レベルのロールバックが行われたトランザクションに対して対応するメッセージが戻されます。ロールバックされる文は、デッドロックが検出されたトランザクションに属しています。通常、通知されたトランザクションは明示的にロールバックする必要がありますが、待機した後でロールバック文を再試行できます。表12-5に、デッドロック状態の2つのトランザクションを示します。

表5デッドロック・トランザクション

T セッション 1 セッション 2 説明
t0
SQL> UPDATE employees
  SET salary = salary*1.1
 WHERE employee_id = 100;

  1 row updated.
SQL> UPDATE employees
 SET salary = salary*1.1
 WHERE employee_id = 200;

  1 row updated.
セッション1でトランザクション1を開始して、従業員100の給与を更新します。セッション2でトランザクション2を開始して、従業員200の給与を更新します。各トランザクションでは、そのトランザクションで更新する行のみがロックされるため、問題は発生しません。
t1
SQL> UPDATE employees
  SET salary = salary*1.1
 WHERE employee_id = 200;

  -- prompt does not return
SQL> UPDATE employees
 SET salary = salary*1.1
 WHERE employee_id = 100;

  -- prompt does not return

トランザクション1で、現在トランザクション2でロックされている従業員200の行の更新を試行します。トランザクション2で、現在トランザクション1でロックされている従業員100の行の更新を試行します。

どちらのトランザクションでも、処理を続行または終了するために必要なリソースを取得できないため、デッドロックが発生します。各トランザクションがいくら待機しても、競合するロックは保持されたままです。

t2
UPDATE employees
 *
 ERROR at line 1:
 ORA-00060: deadlock detected
 while waiting for resource

  SQL>
 

トランザクション1でデッドロックが検出されて、t1で発行されたUPDATE文がロールバックされます。ただし、t0で行われた更新はロールバックされません。セッション1にプロンプトが戻されます。

ノート: デッドロック状態になっているセッションのうちの一方のみが実際にデッドロック・エラーを受信しますが、どちらのセッションもエラーになる可能性があります。

t3
SQL> COMMIT;

  Commit complete.
  セッション1で、t0で行った更新をコミットして、トランザクション1を終了します。t1で正常に行われなかった更新はコミットされません。
t4  
1 row updated.

  SQL>
トランザクション1によってブロックされていた、t1でのトランザクション2による更新が実行されます。プロンプトが戻されます。
t5  
SQL> COMMIT;

  Commit complete.
セッション2で、t0およびt1において行った更新をコミットして、トランザクション2を終了します。

ほとんどの場合、デッドロックは、トランザクションがOracle AI Databaseのデフォルト・ロックを明示的にオーバーライドした場合に発生します。Oracle AI Databaseではロックの段階的拡大は実行されず、問合せでの読取りロックは使用されませんが、行レベルのロッキング(ページ・レベルのロッキングではありません)のみが使用されるため、デッドロックがほとんど起こらない。

関連情報:

自動ロックの概要

Oracle AI Databaseのトランザクションは、トランザクションのかわりにリソースを自動的にロックして、同じリソースへの排他的アクセスを必要とする処理を他のトランザクションで実行しないようにします。

データベースは、リソースおよび実行される操作に応じて、様々な制限レベルの様々なタイプのロックを自動的に取得します。ノート:単純な読取り時に行がロックされることはありません。

Oracle AI Databaseのロックは、次の表に示すカテゴリに分類されます。

表6ロックのカテゴリ

ロック 摘要 詳細を表示するには
DMLロック データを保護します。たとえば、表ロックは表全体をロックし、行ロックは選択された行をロックします。 DMLロック
DDLロック スキーマ・オブジェクトの構造、たとえば表とビューのディクショナリ定義を保護します。 「DDLロック」
システム・ロック データファイルなどの内部データベース構造を保護します。ラッチ、mutexおよび内部ロックは完全に自動的です。 「システム・ロック」

DMLロック

DMLロックは、データ・ロックとも呼ばれているため、複数のユーザーが同時にアクセスするデータの整合性を保証します。

たとえば、DMLロックでは、オンライン・ブック・ショップで在庫が残り1冊となった本を2人の顧客が購入してしまうことを防止します。DMLロックにより、競合するDMLまたはDDL操作を同時に行うことによる破壊的な干渉を防ぎます。

DML文では、次のタイプのロックを自動的に取得します。

次の各項では、各タイプのロックまたはロック・モードの後のカッコ内にある頭字語の略語は、Oracle Enterprise Manager(Enterprise Manager)のロック・モニターで使用される略語です。Enterprise Managerでは、表ロックのモード(RSやSRXなど)が示されるかわりに、すべての表ロックにTMと表示される可能性があります。

行ロック(TX)

行ロック(TXロックとも呼ばれる)は、表の単一の行に対するロックです。トランザクションでは、INSERT、UPDATE、DELETE、MERGEまたはSELECT ... FOR UPDATE文によって変更される各行での行ロックを取得します。行ロックは、トランザクションがコミットまたはロールバックされるまで存在します。

行ロックは、主に2つのトランザクションによる同じ行の変更を防止するためのキューイング・メカニズムとして機能します。変更される行は常に排他モードでロックされるため、ロックを保持しているトランザクションがコミットまたはロールバックされるまで、他のトランザクションはその行を変更できません。行ロックでは、最もきめの細かいロックが実現されるため、最高の同時実行性とスループットが得られます。

ノート:データベースのインスタンス障害が原因でトランザクションが終了した場合は、トランザクション全体がリカバリされる前に、ブロックレベルのリカバリによって行が使用可能になります。

ある行のロックを取得したトランザクションは、その行を含む表のロックも取得します。表ロックによって、現行のトランザクション内のデータ変更をオーバーライドするDDL操作の競合が防止されます。図12-2に、表の行3を更新する例を示します。Oracle AI Databaseでは、更新される行に排他ロックが、表には副排他ロックが自動的に設定されます。

図2: 行ロックと表ロック

画像cncpt265.gifの説明

行ロックと同時実行性

このシナリオは、Oracle AI Databaseで同時実行性のために行ロックが使用されるかを示しています。

3つのセッションで同時に同じ行を問い合せます。セッション1およびセッション2では異なる行に対してコミットせずに更新しますが、セッション3では更新は行われません。各セッションでは、そのセッション自体で行った未コミットの更新を参照できますが、他のセッションによる未コミットの更新は参照できません。

表7データ同時実行性の例

T セッション 1 セッション 2 セッション 3 説明
t0
SELECT employee_id,
 salary
 FROM employees
 WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 512
 101 600
SELECT employee_id,
 salary
  FROM employees
 WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 512
 101 600
SELECT employee_id,
  salary
  FROM employees
 WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 512
 101 600
3つの異なるセッションから、従業員100および101のIDと給与が同時に問い合せます。それぞれの問合せからは、同じ結果が戻されます。
t1
UPDATE hr.employees
 SET salary =
  salary+100
 WHERE
  employee_id=100;
    セッション1で従業員100の給与を更新しますが、コミットはしません。更新時には、書込み側は更新する行に対してのみ行レベル・ロックを取得して、他の書込み側からこの行を変更されないようにします。
t2
SELECT employee_id,
 salary
  FROM employees
  WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 612
 101 600
SELECT employee_id,
 salary
 FROM employees
 WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 512
 101 600
SELECT employee_id,
  salary
  FROM employees
 WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 512
 101 600
各セッションが同時に元の問合せを発行します。セッション1では、t1での更新結果が反映された給与612が表示されます。セッション2およびセッション3における読取りでは、セッション1のトランザクション終了を待機せず、即座に行が戻されます。データベースでは、セッション1での更新前の状態の給与を表示するためにマルチバージョン読取り一貫性が使用されます。
t3  
UPDATE hr.employee
 SET salary =
 salary+100
 WHERE
  employee_id=101;
  セッション2で従業員101の給与を更新しますが、トランザクションをコミットしません。更新時には、書込み側の行レベル・ロックは更新する行に対してのみ行レベル・ロックを取得することで、他の書込み側の行が変更されないようにします。
t4
SELECT employee_id,
 salary
  FROM employees
  WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 612
 101 600
SELECT employee_id,
 salary
 FROM employees
  WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 512
 101 700
SELECT employee_id,
  salary
  FROM employees
 WHERE employee_id
 IN ( 100, 101 );
EMPLOYEE_ID SALARY
 ----------- ------
 100 512
 101 600
各セッションが同時に元の問合せを発行します。セッション1では、t1で更新された給与612が表示されますが、セッション2で更新された従業員101の給与は表示されません。セッション2の読取り側では、セッション2によって更新された給与が表示されますが、セッション1で更新された給与は表示されません。セッション3での読取りでは、読取り一貫性を使用して、セッション1およびセッション2で変更される前の給与が表示されます。

関連情報:

行ロックの記憶域

ロック・マネージャを使用してロックのリストをメモリー内に保持する一部のデータベースとは異なり、Oracle AI Databaseでは、ロックした行を含むデータ・ブロックにロック情報が格納されます。

Oracle Databaseでは、キューイング・メカニズムを使用して、行ロックを取得します。トランザクションで未ロックの行に対するロックが必要となった場合は、データ・ブロックにロックが配置されます。このトランザクションによって変更する各行は、ブロック・ヘッダーに格納されたトランザクションIDのコピーを指しています。

トランザクションが終了しても、トランザクションIDはそのままブロック・ヘッダーに残ります。別のトランザクションで行が変更される場合は、そのトランザクションIDを使用してロックがアクティブであるかどうかが判断されます。ロックがアクティブである場合は、ロックが解除されたときにセッションに通知されるように設定されます。ロックがアクティブでない場合は、そのトランザクションがロックを取得します。

関連情報:

表ロック(TM)

表ロック(TMロックとも呼ばれる)は、表がINSERT、UPDATE、DELETE、MERGE、FOR UPDATE句付きのSELECTまたはLOCK TABLE文によって変更される場合に、トランザクションによって取得されます。

DML操作では、トランザクションのために表へのDMLアクセスを確保して、このトランザクションと競合する可能性のあるDDL操作を防止するために表ロックが必要になります。

表ロックは、次のいずれかのモードで保持できます。

関連情報:

ロックと外部キー

Oracle AI Databaseでは、親キーの同時実行性制御とそれに依存する外部キーの関連において、同時実行性制御は最適化されています。

ロックの動作は、外部キーの列が索引付けされているかどうかに依存します。外部キーが索引付けされていない場合、子表が頻繁にロックされ、デッドロックが発生し、同時実行性が低下する可能性があります。このため外部キーは、ほとんどの場合、索引付けが必要です。唯一の例外は、対応する一意キーまたは主キーの更新や削除が発生しないことが確実な場合です。

ロックと索引のない外部キー

子表の外部キー列に索引が存在せず、セッションによって(行の削除や主キーの属性の変更などで)親表の主キーが変更されるか、親表に行がマージされた場合、データベースは子表に対する完全表ロックを取得します。

次の両方の条件に当てはまる場合、データベースは子表に対する完全表ロックを取得します。

hr.departments表が、索引付けされていない外部キーemployees.department_idを含むhr.employeesの親である場合など。次の図に、departments表の部門60の主キー属性を変更するセッションを示します。

図3: 外部キーの索引がない場合のロック・メカニズム

画像cncpt308.gifの説明

図12-3では、データベースは、部門60の主キーの変更時にemployeesに対する完全表ロックを取得しています。このロックによって、他のセッションはemployees表の問合せはできますが、更新できなくなります。たとえば、セッションでは従業員の電話番号を更新できません。employeesに対する表ロックはdepartments表への主キーの変更が完了すると、即時に解除されます。departmentsの複数の行で主キーの変更が実行される場合、employeesに対する表ロックは、departmentsで変更される行ごとに取得および解除されます。ノート:子表に対するDMLは、親表に対する表ロックを取得しません。

ロックと索引付き外部キー

子表の外部キーの列が索引付けされていて、セッションによって、親表の主キーが変更された場合、データベースは子表の完全テーブルロックを取得しません。また、セッションによって、親表内の主キーが変更された場合(行の削除や、主キーの属性変更など)も、行を親表にマージする場合も、データベースではその子表の主キーがマージされます。

親表に対するロックにより、トランザクションは排他表ロックが、主キーの変更時に、親または子表に対するDMLは阻止されません。この状況は、子表への更新が発生している間に、親表での主キーの変更が発生する場合に適しています。図12-4に、department_id列が索引付けられた子表employeesを示します。トランザクションにより、部門280がdepartmentsから削除されます。この削除により、「ロックと索引のない外部キー」に示すようにデータベースがemployees表に対する完全テーブルロックを取得することはありません。

図4: 外部キーが索引付けされている場合のロック・メカニズム

画像cncpt309.gifの説明

子表でON DELETE CASCADEを指定すると、親表からの削除によって、子表からも削除することができます。たとえば、部門280を削除した場合、削除された部門の従業員に関するレコードをemployeesから削除できます。この場合、待機とロックに関するルールは、親表から行を削除した後に子表から行を削除する場合と同じです。

関連情報:

DDLロック

データ・ディクショナリ・ロック(DDLロック)によって、DDL操作によってオブジェクトに対する処理中または参照中に、そのオブジェクトの定義が保護されています。

DDL操作中には、修正や参照の対象となる個々のスキーマ・オブジェクトのみがロックされます。データ・ディクショナリ全体がロックされることはありません。

Oracle AI Databaseは、DDLロックを必要とするすべてのDDLトランザクションのために、DDLロックを自動的に取得します。ユーザーはDDLロックを明示的に要求できません。たとえば、ユーザーがストアド・プロシージャを作成する場合、Oracle AI Databaseはプロシージャ定義内で参照されるすべてのスキーマ・オブジェクトについてDDLロックを自動的に取得します。DDLロックにより、プロシージャ・コンパイルが完了する前にこれらのオブジェクトの変更または削除が防止されます。

排他DDLロック

排他DDLロックは、他のセッションによるDDLロックまたはDMLロックの取得を防止します。

ほとんどのDDL操作では、同じスキーマ・オブジェクトを変更または参照する可能性のある他のDDL操作によって破壊的な干渉が起きないように、リソースの排他DDLロックが必要です。たとえば、ALTER TABLEで表に列を追加している間は、DROP TABLE操作でその表を削除できず、その逆も同様です。

排他DDLロックはDDL文実行の継続中と自動コミット中ずっと継続します。排他DDLロックの取得では、別の操作によってそのスキーマ・オブジェクトに対して別のDDLロックが保持されている場合、その取得は古いDDLロックが解除されるまで待機し、その後に処理されます。

関連項目: 「共有DDLロック」では、破壊的干渉を防止するううえで排他ロックが不要である状況について説明します

共有DDLロック

リソースに対する共有DDLロックでは、競合するDDL操作によって破壊的な干渉が防止されますが、同様のDDL操作でのデータ同時実行性は確保されます。

たとえば、CREATE PROCEDURE文の実行時には、その文を含むトランザクションは、参照されるすべての表について共有DDLロックを取得します。他のトランザクションでは、同じ表を参照するプロシージャを同時作成し、同じ表に対する共有DDLロックを同時取得できますが、参照される表に対して排他DDLロックを取得できるトランザクションはありません。

共有DDLロックはDDL文実行および自動コミットの間ずっと存続します。その結果、共有DDLロックを保持するトランザクションでは、参照中のスキーマ・オブジェクトの定義がそのトランザクションの継続時間にわたって変化しないことが保証されます。

ブレーク可能解析ロック

SQL文またはPL/SQLプログラム・ユニットは、参照する各スキーマ・オブジェクトについて解析ロックを保持します。

参照オブジェクトが変更または削除された場合に、対応する共有SQL領域を無効にできるようにするため、解析ロックは取得されます。解析ロックは、どのようなDDL操作 も拒否せず、矛盾するDDL操作も許可するためにブレーク(中断)できるため、ブレーク可能解析ロックと呼ばれます。

解析ロックは、SQL文実行の解析フェーズ中に共有プールで取得します。このロックは、その文の共有SQL領域がその共有プールに残っているかぎり保持されます。

関連項目: 「共有プール」

システム・ロック

Oracle AI Databaseでは、様々なタイプのシステム・ロックを使用して、内部データベースおよびメモリー構造を保護します。ユーザーは、システム・ロックの出現や継続期間を制御できないため、このメカニズムにはアクセスできません。

ラッチ

ラッチは、共有データ構造、オブジェクトおよびファイルへのマルチユーザー・アクセスを調整する、単純な低レベルのシリアライズ化メカニズムである。

ラッチは、共有メモリー・リソースが複数プロセスによってアクセスされるときに破損しないように保護します。特に、ラッチは次の状況からデータ構造を保護します。

通常、1つのラッチによってSGA内の複数のオブジェクトが保護されます。たとえば、DBWやLGWRなどのバックグラウンドプロセスでは、共有プールのメモリーを割り当てしてデータ構造を作成します。このメモリーを割り当てるために、これらのプロセスは、アクセスをシリアライズする共有プール・ラッチを使用して、2つのプロセスが共有プールを同時に検査または変更できないようにします。メモリーが割り当てられた後、解析に必要なライブラリ・キャッシュなどの共有プール領域に他のプロセスがアクセスする必要がある場合があります。この場合、共有プール全体ではなくライブラリ・キャッシュのみがラッチされます。

行ロックなどのエンキュー・ラッチとは異なり、ラッチではセッションのキューイングは許可されません。ラッチが使用可能になると、ラッチを要求する最初のセッションがラッチへの排他的アクセスを取得します。ラッチスピンの現象は、プロセスがループ内のラッチを繰り返しリクエストし、プロセスがラッチ要求を更新する前にCPUを解放するとラッチ・スリープが発生すると発生します。

通常、Oracleプロセスは、データ構造の1つを操作または参照する、非常に短い間のみラッチを取得します。たとえば、1人の従業員の給与更新の処理中に、データベースは数千のラッチを取得および解除する場合があります。ラッチの実装(特に、プロセスがラッチを待機するかどうか、およびどのくらいの時間待機するか)は、オペレーティング・システムに依存します。

ラッチの数を増やすと、同時実行可能な操作の数が減少します。たとえば、過剰なハード解析操作によって、ライブラリ・キャッシュ・ラッチの競合が生じます。V$LATCHビューには、各ラッチが要求された回数や待機された回数を含む、各ラッチの詳細な使用統計が含まれています。

関連情報:

Mutex

相互排他オブジェクト(mutex)は、メモリー内のオブジェクトが同時プロセスによってアクセスされた場合にエージ・アウトまたは破損しないようにするための低レベルのメカニズムです。mutexはラッチに似ていますが、通常、ラッチではオブジェクトのグループが保護されるのに対して、mutexでは単一のオブジェクトが保護されます。

mutexには、複数の利点があります。

内部ロック

内部ロックは、ラッチやmutexよりも高レベルで複雑なメカニズムであり、様々な目的に使用されます。

データベースでは、次のタイプの内部ロックを使用します。

関連項目: 「データ辞書キャッシュ」

手動データ・ロックの概要

Oracle AI Databaseのデフォルトのロック・メカニズムは、手動でオーバーライドできます。

データの同時実行性、データの整合性および文レベルの読取り一貫性が確保するために、Oracle AI Databaseは自動的にロックを実行します。ただし、デフォルト・ロックの置換えは、次のような状況で有効です。

Oracle AI Databaseの自動ロックは、セッション・レベルまたはトランザクション・レベルでオーバーライドできます。セッション・レベルでは、ALTER SESSION文を使用して必要なトランザクション分離レベルを設定できます。トランザクション・レベルでは、次のSQL文を含むトランザクションがOracle AI Databaseのデフォルト・ロックをオーバーライドします。

前述の文で取得したロックは、トランザクション終了後に解除されるか、セーブポイントへのロールバックによって解除されます。

Oracle AI Databaseのデフォルト・ロックを任意のレベルで上書きする場合、データベース管理者やアプリケーション開発者は、ロックのオーバーライドの手順が確実に正しく実行されるようにしてください。ロックの手順は、データ整合性が保証される、データ同時実行性が許容範囲内である、デッドロックは発生する可能性がないかまたは適切に処理される、などの基準を満たすものにする必要があります。

関連情報:

ユーザー定義ロックの概要

Oracle AI Databaseのロックマネージメント・サービスを使用すると、特定のアプリケーションで独自のロックを定義できます。

たとえば、ファイル・システム上のメッセージ・ログに対するアクセスをシリアライズするためのロックを作成できます。確保されたユーザー・ロックは、Oracle AI Databaseロックと同一であるため、デッドロックの検出などのOracle AI Databaseロックの機能をすべて備えています。ユーザー・ロックの接頭辞はULで識別されるため、Oracle AI Databaseロックと矛盾することはありません。

Oracle AI Databaseのロック管理サービスは、DBMS_LOCKパッケージ内のプロシージャを介して利用できます。PL/SQLブロックには、次の処理を行う文を含めることができます。

関連情報:


脚注の説明

脚注1:

分散トランザクションの2フェーズ・コミットを処理する場合、特殊な状況では、データベースで読取りアクセスが一時的に禁止されることがあります。具体的には、問合せが準備フェーズとコミット・フェーズの間に開始され、コミット前にデータの読取りを試みる場合、データベースでは、読取りの整合性を保証するため、行レベルからブロック・レベルにロックが拡大されます。