Oracle Database 管理者ガイド 11gリリース1(11.1) E05760-03 |
|
この章の内容は次のとおりです。
分散トランザクションでどのノードが最初にコミットされるかは、最も高いコミット・ポイント強度を持つデータベースによって決まります。各ノードのコミット・ポイント強度を指定するときは、準備フェーズまたはコミット・フェーズ中に障害が発生した場合に最も重要なサーバーがブロックされないようにしてください。ノードのコミット・ポイント強度は、COMMIT_POINT_STRENGTH
初期化パラメータによって指定します。
デフォルト値は、オペレーティング・システムによって異なります。値の範囲は、0(ゼロ)から255までの任意の整数です。たとえば、データベースのコミット・ポイント強度を200に設定するには、そのデータベースの初期化パラメータ・ファイルに次の行を追加します。
COMMIT_POINT_STRENGTH = 200
コミット・ポイント強度は、分散トランザクションでコミット・ポイント・サイトを決定する際にのみ使用されます。
データベースのコミット・ポイント強度を設定するときは、次の点を考慮してください。
トランザクションの命名が可能です。この機能は、特定の分散トランザクションを識別する際に便利であり、同じ目的のCOMMIT COMMENT
文にかわるものです。
トランザクションに命名するにはSET TRANSACTION...NAME
文を使用します。次に例を示します。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE NAME 'update inventory checkpoint 0';
この例は、SERIALIZABLE
に等しい分離レベルを持つ新しいトランザクションをユーザーが開始し、それに'update inventory checkpoint 0'
という名前を付けたことを示しています。
分散トランザクションでは、トランザクションがコミットされるときに、名前が参加サイトに送られます。トランザクション名が存在する場合は、COMMIT COMMENT
があっても無視されます。
トランザクション名は、V$TRANSACTION
ビューのNAME
列に表示され、トランザクションがコミットされると、DBA_2PC_PENDINGビューのTRAN_COMMENT
フィールドに表示されます。
各データベースのデータ・ディクショナリには、オープンしているすべての分散トランザクションに関する情報が格納されています。データ・ディクショナリの表とビューを使用すると、トランザクションに関する情報を取得できます。この項の内容は、次のとおりです。
次のビューには、ローカル・データベースで定義され、データ・ディクショナリに格納されているデータベース・リンクが表示されます。
ビュー | 用途 |
---|---|
DBA_2PC_PENDING |
インダウト分散トランザクションがすべてリストされます。このビューには、インダウト・トランザクションが移入されるまで何もデータが入っていません。トランザクションが解決された後、ビューはパージされます。 |
このビューは、特定のトランザクションIDのグローバル・コミット番号を判断するために使用します。このグローバル・コミット番号は、インダウト・トランザクションを手動で解決するときに使用できます。
関連性の最も高い列を次の表に示します(ビューのすべての列の詳細は、『Oracle Databaseリファレンス』を参照してください)。
DBA_2PC_PENDING
の関連情報を問い合せるには、次のスクリプトpending_txn_script
を実行します(出力例も含まれています)。
COL LOCAL_TRAN_ID FORMAT A13 COL GLOBAL_TRAN_ID FORMAT A30 COL STATE FORMAT A8 COL MIXED FORMAT A3 COL HOST FORMAT A10 COL COMMIT# FORMAT A10 SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID, STATE, MIXED, HOST, COMMIT# FROM DBA_2PC_PENDING / SQL> @pending_txn_script LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE MIX HOST COMMIT# ------------- ------------------------------ -------- --- ---------- ---------- 1.15.870 HQ.ACME.COM.ef192da4.1.15.870 commit no dlsun183 115499
この出力は、ローカル・トランザクション1.15.870
がこのノードではコミットを完了しているものの、他の1つ以上のノードで保留している可能性があることを示しています。LOCAL_TRAN_ID
とGLOBAL_TRAN_ID
のローカル部分が同じなので、このノードはトランザクションのグローバル・コーディネータです。
次のビューには、リモート・クライアントから受信されるインダウト・トランザクションと、リモート・サーバーに送信されるインダウト・トランザクションが表示されます。
トランザクションがインダウトのときは、セッション・ツリー内のどのノードがどのロールを実行しているのかを判断することが必要な場合があります。このビューを使用すると、次のことが判断できます。
関連性の最も高い列を次の表に示します(ビューのすべての列の詳細は、『Oracle Databaseリファレンス』を参照してください)。
DBA_2PC_PENDING
の関連情報を問い合せるには、次のスクリプトneighbors_script
を実行します(出力例も含まれています)。
COL LOCAL_TRAN_ID FORMAT A13 COL IN_OUT FORMAT A6 COL DATABASE FORMAT A25 COL DBUSER_OWNER FORMAT A15 COL INTERFACE FORMAT A3 SELECT LOCAL_TRAN_ID, IN_OUT, DATABASE, DBUSER_OWNER, INTERFACE FROM DBA_2PC_NEIGHBORS / SQL> CONNECT SYS@hq.acme.com AS SYSDBA SQL> @neighbors_script LOCAL_TRAN_ID IN_OUT DATABASE DBUSER_OWNER INT ------------- ------ ------------------------- --------------- --- 1.15.870 out SALES.ACME.COM SYS C
この出力は、トランザクション1.15.870
をコミットするための送信要求をローカル・ノードがリモート・サーバーsales
に送ったことを示します。sales
がトランザクションをコミットしたものの、他のノードがコミットしなかった場合は、sales
がコミット・ポイント・サイトであることが判明します。コミット・ポイント・サイトは、常に最初にコミットされるためです。
2フェーズ・コミットの間に障害が発生すると、トランザクションはインダウトになります。分散トランザクションがインダウトになる要因は、次のとおりです。
ローカルのインダウト分散トランザクションは、手動で強制的にコミットまたはロールバックできます。この操作では一貫性の問題が生じる可能性があるため、特定の条件が成り立つとき以外は実行しないでください。
この項の内容は、次のとおりです。
分散トランザクションをコミットするユーザー・アプリケーションには、次のいずれかのエラー・メッセージによって問題が通知されます。
ORA-02050: トランザクションIDはロールバックされました。 some remote dbs may be in-doubt ORA-02053: トランザクションIDはコミットしました。 some remote dbs may be in-doubt ORA-02054: トランザクションIDはインダウトです
アプリケーションでこれらのエラーを受け取った場合は、トランザクションに関する情報を保存するようにしてください。この情報は、後で分散トランザクションの手動リカバリが必要になった場合に使用できます。
ネットワークまたはシステムの障害のために、任意のノードでインダウト分散トランザクションが1つ以上発生した場合でも、そのノードの管理者がなんらかの処理を実行する必要はありません。ネットワークやシステムの障害が解決した後、データベースの自動リカバリ機能によって、セッション・ツリーのすべてのノードが同じ結果になるように(つまり、すべてコミットされるかすべてロールバックされる)、すべてのインダウト・トランザクションの処理が透過的に完了します。
ただし、障害が長期にわたる場合には、トランザクションを強制的にコミットまたはロールバックすることで、ロックされたデータをすべて解放できます。アプリケーションは、この操作を想定しておく必要があります。
次の条件が成り立つときのみ、特定のインダウト・トランザクションを手動で上書きしてください。
ORA-01591
エラー・メッセージによってユーザーのトランザクションが妨げられたときに起こります。
DBA_2PC_PENDING
にリストされます。
通常は、他の場所の管理者と相談した上で、インダウト分散トランザクションを強制的にローカルに処理するかどうかを決めてください。判断を誤った場合は、トレースの困難なデータベースの非一貫性が生じる可能性があります。この非一貫性は、手動で訂正する必要があります。
前述の条件が当てはまらない場合は、必ずデータベースの自動リカバリ機能によってトランザクションを完了するようにしてください。しかし、前述のいずれかの条件に当てはまる場合には、インダウト・トランザクションのローカルでの修正を検討してください。
トランザクションの強制完了を決めた場合は、次の目的に留意しながら、使用可能な情報を分析します。
DBA_2PC_PENDING
ビューを使用し、トランザクションをコミットまたはロールバックしたノードを探します。トランザクションをすでに解決しているノードが見つかった場合は、そのノードで実行された処理に従うことができます。
DBA_2PC_PENDING
のTRAN_COMMENT
列に、対象の分散トランザクションに関するなんらかの情報が与えられていないかを確認します。コメントは、COMMIT
文のCOMMENT
句で指定されます。また、トランザクションに命名している場合は、トランザクションがコミットされたときに、トランザクション名がTRAN_COMMENT
フィールドに設定されます。
たとえば、インダウト分散トランザクションのコメントで、トランザクションの開始元とタイプを示すことができます。
COMMIT COMMENT 'Finance/Accts_pay/Trans_type 10B';
また、この情報をトランザクション名として提供するために、SET TRANSACTION...NAME
文を使用することも可能です。
DBA_2PC_PENDING
のADVICE
列に、対象の分散トランザクションに関するなんらかの情報が与えられていないかを確認します。アプリケーションでALTER SESSION
文のADVISE
句を使用すれば、分散トランザクションの別々の部分を強制的にコミットまたはロールバックする際のアドバイスを規定できます。
準備フェーズ中に各ノードに送られたアドバイスは、現行トランザクション内でそのデータベースに対し最新のDML文が実行されたときに有効なアドバイスです。
たとえば、あるノードのemp
表から別のノードのemp
表に従業員レコードを移動する分散トランザクションを考えます。次の一連のSQL文を追加することによって、管理者が各ノードで個別にインダウト・トランザクションを強制的に完了した場合でも、トランザクションでレコードを保護できます。
ALTER SESSION ADVISE COMMIT; INSERT INTO emp@hq ... ; /*advice to commit at HQ */ ALTER SESSION ADVISE ROLLBACK; DELETE FROM emp@sales ... ; /*advice to roll back at SALES*/ ALTER SESSION ADVISE NOTHING;
与えられたアドバイスに従ってインダウト・トランザクションを手動で強制的に完了すると、最悪の場合、各ノードに従業員レコードがコピーされ、消去できなくなる可能性があります。
COMMIT
文またはROLLBACK
文に、FORCE
オプションと、コミットまたはロールバックするインダウト・トランザクションのローカル・トランザクションIDまたはグローバル・トランザクションIDを示すテキスト文字列を指定します。
この項の内容は、次のとおりです。
トランザクションのコミットを試みる前に、適正な権限を持っていることを確認してください。必要な権限は次のとおりです。
トランザクションをコミットするユーザー | 必要な権限 |
---|---|
管理者 |
|
別のユーザー |
|
次のSQL文は、インダウト・トランザクションをコミットします。
COMMIT FORCE 'transaction_id';
変数transaction_idは、DBA_2PC_PENDING
データ・ディクショナリ・ビューのLOCAL_TRAN_ID
列またはGLOBAL_TRAN_ID
列のどちらかで指定されているトランザクション識別子です。
たとえば、DBA_2PC_PENDING
を問い合せて、分散トランザクションのLOCAL_TRAN_ID
が1:45.13
であることを確認するとします。
そして、次のSQL文を発行し、このインダウト・トランザクションのコミットを強制実行します。
COMMIT FORCE '1.45.13';
必要であれば、トランザクションを強制的にコミットするときに、トランザクションのSCNを指定することもできます。この機能を使用すると、他のノードでトランザクションがコミットされたときに割り当てられたSCNを使用して、インダウト・トランザクションをコミットできます。
これにより、障害が発生した場合でも、分散トランザクションのコミット時間の同期を保つことができます。SCNは、別のノードですでにコミットされた同じトランザクションのSCNが判別できるときのみ指定してください。
たとえば、次のグローバル・トランザクションIDを使用してトランザクションを手動でコミットするとします。
SALES.ACME.COM.55d1c563.1.93.29
まず、対象のトランザクションに関係しているリモート・データベースのDBA_2PC_PENDING
ビューを問い合せます。次に、そのノードでトランザクションのコミットに使用されたSCNをメモします。そして、ローカル・ノードでトランザクションをコミットするときにこのSCNを指定します。たとえば、SCNが829381993
の場合は、次の文を発行します。
COMMIT FORCE 'SALES.ACME.COM.55d1c563.1.93.29', 829381993;
インダウト分散トランザクションのロールバックを試みる前に、適正な権限を持っていることを確認してください。必要な権限は次のとおりです。
トランザクションをコミットするユーザー | 必要な権限 |
---|---|
管理者 |
|
別のユーザー |
|
次のSQL文は、インダウト・トランザクションをロールバックします。
ROLLBACK FORCE 'transaction_id';
変数transaction_idは、DBA_2PC_PENDING
データ・ディクショナリ・ビューのLOCAL_TRAN_ID
列またはGLOBAL_TRAN_ID
列のどちらかで指定されているトランザクション識別子です。
たとえば、ローカル・トランザクションIDが2.9.4
のインダウト・トランザクションをロールバックするには、次の文を使用します。
ROLLBACK FORCE '2.9.4';
インダウト・トランザクションは、RECO(リカバラ・プロセス)によってリカバリされる前に、DBA_2PC_PENDING.STATE
列にCOLLECTING
、COMMITTED
またはPREPARED
として表示されます。COMMIT FORCE
またはROLLBACK FORCE
を使用してインダウト・トランザクションを強制的に完了すると、FORCED COMMIT
またはFORCED ROLLBACK
の状態になることがあります。
自動リカバリでは通常、これらの状態にあるエントリが削除されます。唯一の例外として、リカバリ時に、トランザクション内の他のサイトと一貫性のない状態にある強制トランザクションが検出されるときがあります。この場合は、エントリが表内に残る可能性があり、DBA_2PC_PENDING
のMIXED
列の値がYES
になります。これらのエントリは、DBMS_TRANSACTION.PURGE_MIXED
プロシージャを使用してクリーンアップできます。
リモート・データベースが永続的に失われたために自動リカバリが不可能な場合は、データベースを再作成してもリカバリではそのデータベースを識別できません。これは、再作成時に新しいデータベースIDが割り当てられるためです。この場合は、DBMS_TRANSACTION
パッケージのPURGE_LOST_DB_ENTRY
プロシージャを使用して、エントリをクリーンアップする必要があります。このエントリによってデータベース・リソースが保持されることはないため、エントリのクリーンアップを急ぐ必要はありません。
エントリをデータ・ディクショナリから手動で削除するには、次の構文を使用します(ここで、trans_idはトランザクションの識別子を表します)。
DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('trans_id');
たとえば、保留中の分散トランザクション1.44.99
をパージするには、SQL*Plusで次の文を入力します。
EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.44.99');
このプロシージャは、自動リカバリによってトランザクションを解決できないほどの大幅な再構成を行った場合にのみ実行してください。たとえば、次のような場合です。
次の表は、分散トランザクションに関する各種の状態と、それに対して管理者が実行すべき処理を示したものです。
図33-1は、分散トランザクションのコミット中の障害を示しています。この障害例では、準備フェーズは完了しています。しかし、コミット・フェーズ時に、コミット・ポイント・サイトがトランザクションをコミットしていても、コミット・ポイント・サイトのコミット確認がグローバル・コーディネータに到達しません。インダウト・トランザクションは他のトランザクションにとっても重要なものであるため、在庫データはロックされており、アクセスできません。また、インダウト・トランザクションがコミットまたはロールバックされるまで、ロックが必ず保持されます。
次の手順に従って、インダウト・トランザクションのローカル部分を手動で強制完了できます。詳細は、以降の項を参照してください。
手順3: ローカル・ノードでのDBA_2PC_NEIGHBORSの問合せ
手順4: 全ノードでのデータ・ディクショナリ・ビューの問合せ
手順6: DBA_2PC_PENDINGを使用したMIXED結果のチェック
インダウト・トランザクションのロックと競合を起こしているローカル・データベース・システムのユーザーは、次のエラー・メッセージを受け取ります。
ORA-01591: インダウト分散トランザクション1.21.17がロックを保持しています。
この場合、1.21.17
はインダウト分散トランザクションのローカル・トランザクションIDです。どのインダウト・トランザクションを強制処理すればよいかを特定するために、問題を報告したユーザーからこのID番号を聞き、記録しておきます。
SQL*Plusを使用してwarehouse
に接続した後、ローカルのDBA_2PC_PENDING
データ・ディクショナリ・ビューを問い合せて、インダウト・トランザクションに関する情報を取得します。
CONNECT SYS@warehouse.acme.com AS SYSDBA SELECT * FROM DBA_2PC_PENDING WHERE LOCAL_TRAN_ID = '1.21.17';
データベースは次の情報を返します。
Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.21.17 GLOBAL_TRAN_ID SALES.ACME.COM.55d1c563.1.93.29 STATE prepared MIXED no ADVICE TRAN_COMMENT Sales/New Order/Trans_type 10B FAIL_TIME 31-MAY-91 FORCE_TIME RETRY_TIME 31-MAY-91 OS_USER SWILLIAMS OS_TERMINAL TWA139: HOST system1 DB_USER SWILLIAMS COMMIT#
グローバル・トランザクションIDは、分散トランザクションのすべてのノードで同一である共通のトランザクションIDです。次のような書式で記録されています。
global_database_name
.hhhhhhhh.local
_transaction_id
各項目の意味は次のとおりです。
global_database_name
は、グローバル・コーディネータのデータベース名です。
hhhhhhhh
は、グローバル・コーディネータの内部データベース識別子(16進値)です。
local_transaction_id
は、グローバル・コーディネータで割り当てられた、対応するローカル・トランザクションIDです。
グローバル・コーディネータでは、グローバル・トランザクションIDの最後の部分とローカル・トランザクションIDが一致します。この例ではこれらの番号が一致しないので、warehouse
はグローバル・コーディネータでないことがわかります。
LOCAL_TRAN_ID 1.21.17 GLOBAL_TRAN_ID ... 1.93.29
このノードのトランザクションは、準備完了状態です。
STATE prepared
したがって、warehouse
は、自身のコーディネータからコミット要求またはロールバック要求が送られてくるのを待っています。
トランザクションのコメントまたはアドバイスに、このトランザクションに関する情報が含まれている可能性があります。トランザクションに関する情報が含まれていれば、そのコメントを利用します。この例では、トランザクションのコメントに開始元とトランザクション・タイプが含まれています。
TRAN_COMMENT Sales/New Order/Trans_type 10B
また、SET TRANSACTION...NAME
文によって、トランザクションに関する情報がトランザクション名として提供されている可能性もあります。
この情報から、トランザクションのローカル部分をコミットすべきか、またはロールバックすべきかを決める際に役立つ情報を得ることができます。インダウト・トランザクションに有益なコメントが付けられていない場合は、その他の管理作業を実行し、セッション・ツリーをトレースして、トランザクションをすでに解決しているノードを探す必要があります。
この手順の目的は、セッション・ツリーを探索してコーディネータを見つけ、最終的にグローバル・コーディネータに到達することです。それと同時に、トランザクションをすでに解決しているコーディネータが見つかる場合もあります。トランザクションをすでに解決しているコーディネータが見つからない場合は、最終的にコミット・ポイント・サイトを探し出します。コミット・ポイント・サイトでは、常にインダウト・トランザクションが解決されています。セッション・ツリーをトレースするには、各ノードのDBA_2PC_NEIGHBORS
ビューを問い合せます。
この例では、warehouse
データベースでこのビューを問い合せます。
CONNECT SYS@warehouse.acme.com AS SYSDBA SELECT * FROM DBA_2PC_NEIGHBORS WHERE LOCAL_TRAN_ID = '1.21.17' ORDER BY SESS#, IN_OUT; Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.21.17 IN_OUT in DATABASE SALES.ACME.COM DBUSER_OWNER SWILLIAMS INTERFACE N DBID 000003F4 SESS# 1 BRANCH 0100
DBA_2PC_NEIGHBORS
ビューは、インダウト・トランザクションに対応付けられた接続に関する情報を提供します。情報は、接続が受信(IN_OUT = in
)か送信(IN_OUT = out
)かによって異なります。
この例では、IN_OUT
列によって、warehouse
データベースがsales
クライアント(DATABASE列に示されている)のサーバーであることがわかります。
IN_OUT in DATABASE SALES.ACME.COM
warehouse
への接続は、swilliams
アカウント(DBUSER_OWNER
列に示されている)からのデータベース・リンクを介して確立されています。
DBUSER_OWNER SWILLIAMS
この他、INTERFACE
列によって、ローカル・ノードまたは下位ノードがコミット・ポイント・サイトなのかどうかがわかります。
INTERFACE N
INTERFACE
列が示すように、warehouse
もその子もコミット・ポイント・サイトではありません。
この時点で、各設置ノードの管理者に連絡を取り、グローバル・トランザクションIDを使用して手順2および3を繰り返すように各管理者に依頼できます。
たとえば、sales
およびhq
で手順2および3を実行すると、次の結果が返されます。
この段階では、sales
の管理者がDBA_2PC_PENDING
データ・ディクショナリ・ビューを問い合せます。
SQL> CONNECT SYS@sales.acme.com AS SYSDBA SQL> SELECT * FROM DBA_2PC_PENDING > WHERE GLOBAL_TRAN_ID = 'SALES.ACME.COM.55d1c563.1.93.29'; Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.93.29 GLOBAL_TRAN_ID SALES.ACME.COM.55d1c563.1.93.29 STATE prepared MIXED no ADVICE TRAN_COMMENT Sales/New Order/Trans_type 10B FAIL_TIME 31-MAY-91 FORCE_TIME RETRY_TIME 31-MAY-91 OS_USER SWILLIAMS OS_TERMINAL TWA139: HOST system1 DB_USER SWILLIAMS COMMIT#
次に、sales
の管理者はDBA_2PC_NEIGHBORS
を問い合せて、グローバル・コーディネータ、ローカル・コーディネータおよびコミット・ポイント・サイトを判別します。
SELECT * FROM DBA_2PC_NEIGHBORS WHERE GLOBAL_TRAN_ID = 'SALES.ACME.COM.55d1c563.1.93.29' ORDER BY SESS#, IN_OUT;
この問合せは、次の3行を返します。
warehouse
接続の行に対応する情報を、書式を変えて示すと次のようになります。
Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.93.29 IN_OUT OUT DATABASE WAREHOUSE.ACME.COM DBUSER_OWNER SWILLIAMS INTERFACE N DBID 55d1c563 SESS# 1 BRANCH 1
hq
接続の行に対応する情報を、書式を変えて示すと次のようになります。
Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.93.29 IN_OUT OUT DATABASE HQ.ACME.COM DBUSER_OWNER ALLEN INTERFACE C DBID 00000390 SESS# 1 BRANCH 1
前の問合せから得られた情報によって、次のことがわかります。
sales
のローカル・トランザクションIDとグローバル・トランザクションIDが一致しているので、sales
はグローバル・コーディネータです。
sales
は別のノードのサーバーではありません。
hq
またはそのサーバーの1つです。
この段階では、hq
の管理者がDBA_2PC_PENDING
データ・ディクショナリ・ビューを問い合せます。
SELECT * FROM DBA_2PC_PENDING@hq.acme.com WHERE GLOBAL_TRAN_ID = 'SALES.ACME.COM.55d1c563.1.93.29'; Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.45.13 GLOBAL_TRAN_ID SALES.ACME.COM.55d1c563.1.93.29 STATE COMMIT MIXED NO ACTION TRAN_COMMENT Sales/New Order/Trans_type 10B FAIL_TIME 31-MAY-91 FORCE_TIME RETRY_TIME 31-MAY-91 OS_USER SWILLIAMS OS_TERMINAL TWA139: HOST SYSTEM1 DB_USER SWILLIAMS COMMIT# 129314
この時点で、トランザクションを解決しているノードが見つかりました。ビューが示しているように、このノードではコミットが完了しており、コミットID番号が割り当てられています。
STATE COMMIT COMMIT# 129314
したがって、自分のローカル・データベースでインダウト・トランザクションを強制的にコミットできます。この調査結果を他の管理者に伝えれば、他の場所での解決にも役立つ可能性があります。
sales
データベースの管理者と連絡を取り、グローバルIDを使用してインダウト・トランザクションを手動でコミットしてもらうように依頼します。
SQL> CONNECT SYS@sales.acme.com AS SYSDBA SQL> COMMIT FORCE 'SALES.ACME.COM.55d1c563.1.93.29';
同時に、warehouse
データベースの管理者として、グローバルIDを使用してインダウト・トランザクションを手動でコミットします。
SQL> CONNECT SYS@warehouse.acme.com AS SYSDBA SQL> COMMIT FORCE 'SALES.ACME.COM.55d1c563.1.93.29';
トランザクションを手動で強制的にコミットまたはロールバックした後も、ペンディング・トランザクション表の対応する行はそのまま残っています。トランザクションの状態は、トランザクションをどのように強制完了したかに応じて変わります。
Oracle Databaseには、必ずペンディング・トランザクション表があります。これは、2フェーズ・コミットの各フェーズの進行に従って分散トランザクションに関する情報を格納する特別な表です。データベースのペンディング・トランザクション表は、DBA_2PC_PENDING
データ・ディクショナリ・ビューを介して問い合せることができます(詳細は表33-1を参照)。
また、ペンディング・トランザクション表で特に重要なものとして、DBA_2PC_PENDING.MIXED
に示されるMIXED結果フラグがあります。ペンディング・トランザクションを強制的にコミットまたはロールバックする場合は、選択を誤る可能性があります。たとえば、ローカル管理者がトランザクションをロールバックしたにもかからわず、他のノードではそのトランザクションをコミットしてしまうといったことが考えられます。このような誤った判断は自動的に検出され、対応するペンディング・トランザクションのレコードに損傷フラグが設定されます(MIXED=yes
)。
RECOバックグラウンド・プロセスは、ペンディング・トランザクション表の情報を使用して、インダウト・トランザクションの状態を最終決定します。また、管理者がペンディング・トランザクション表の情報を使用して、保留中の分散トランザクションの自動リカバリ手順を手動で上書きすることもできます。
RECOによって自動的に解決されたトランザクションは、すべてペンディング・トランザクション表から削除されます。また、管理者によって正しく解決されたインダウト・トランザクションに関する情報も、RECOが通信を再確立したときにチェックされて、すべてペンディング・トランザクション表から自動的に削除されます。ただし、管理者が解決したことによってノード間にまたがってMIXEDの結果が生じた行は、DBMS_TRANSACTIONS.PURGE_MIXED
を使用して手動で削除しないかぎり、関係しているすべてのノードのペンディング・トランザクション表にそのまま残ります。
SQL文を発行すると、データベースは文を正常に実行するために必要なリソースのロックを試みます。しかし、要求されたデータが、コミットされていない他のトランザクションの文によって現在保持されていて、長時間ロックされたままになっていると、タイムアウトが発生します。
データ・アクセスの障害に関しては、次の事例について考慮してください。
リモート・データベースのロックを必要とするDML文は、要求したデータのロックを別のトランザクションが所有している場合にブロックされる可能性があります。このようなロックによってSQL文の要求がブロックされ続けると、次の一連のイベントが発生します。
ORA-02049: タイムアウト: 分散トランザクションがロックを待機しています。
トランザクションによってデータは変更されていないので、タイムアウトの結果として必要な処理はありません。アプリケーションでは、デッドロックが発生したものとして処理を継続してください。文を実行したユーザーは、後で同じ文の再実行を試みることができます。それでもロックが続く場合には、ユーザーは管理者に連絡して問題を報告してください。
ローカル・データベースのロックを必要とする問合せまたはDML文は、インダウト分散トランザクションによるリソースのロックのために無期限にブロックされる可能性があります。この場合、データベースは次のエラー・メッセージを発行します。
ORA-01591: インダウト分散トランザクションidentifierがロックを保持しています。
この場合、データベースはSQL文をただちにロールバックします。文を実行したユーザーは、後で同じ文の再実行を試みることができます。それでもロックが続く場合には、ユーザーは管理者に連絡して問題を報告してください。このとき、インダウト分散トランザクションのIDも併せて報告してください。
2フェーズ・コミットの重要な部分の処理中に障害が発生する確率は低いため、このような状況が起こる可能性はほとんどありません。仮にこのような障害が発生した場合でも、ネットワーク障害やシステム障害から迅速にリカバリできれば、手動で介入しなくても問題は自動的に解決されます。したがって、この種の問題は、ユーザーやDBAに検出される前に解決されるのが普通です。
分散トランザクションの障害は、次のような理由で強制的に発生させることができます。
ここでは、使用可能な機能とその操作に必要な手順を説明します。
COMMIT
文のCOMMENT
パラメータには、コメントを挿入できます。分散トランザクションの2フェーズ・コミットのフェーズ時に意図して障害を発生させるには、COMMENT
パラメータに、次のコメントを挿入します。
COMMIT COMMENT 'ORA-2PC-CRASH-TEST-n';
コメント内のnには、次の整数のいずれかが入ります。
たとえば、ローカルのコミット・ポイント強度がリモートのコミット・ポイント強度よりも高く、双方のノードが更新されている場合、次の文では、次のメッセージが返されます。
COMMIT COMMENT 'ORA-2PC-CRASH-TEST-7'; ORA-02054: トランザクション1.93.29はインダウトです。 ORA-02059: コミット・コメントにORA-2PC-CRASH-TEST-7が含まれています。
この時点で、インダウト分散トランザクションがDBA_2PC_PENDING
ビューに表示されます。対応している場合は、RECOがそのトランザクションを自動的に解決します。
Oracle DatabaseインスタンスのRECOバックグラウンド・プロセスは、分散トランザクションに伴う障害を自動的に解決します。ノードのRECOバックグラウンド・プロセスは、時間間隔を指数関数的に広げながら、インダウト分散トランザクションのローカル部分のリカバリを試みます。
RECOは、障害を起こしたトランザクションに関係している他のノードに対して、既存の接続を使用するか、または新しい接続を確立できます。接続が確立されると、RECOはすべてのインダウト・トランザクションを自動的に解決します。各データベースのペンディング・トランザクション表内にインダウト・トランザクションに対応している行があれば、自動的に削除されます。
ENABLE
/DISABLE DISTRIBUTED RECOVERY
オプションを指定してALTER SYSTEM
文を使用すると、RECOを使用可能または使用禁止にできます。たとえば、RECOを一時的に使用禁止にして2フェーズ・コミットの障害を強制的に発生させ、インダウト・トランザクションを手動で解決できます。
次の文は、RECOを使用禁止にします。
ALTER SYSTEM DISABLE DISTRIBUTED RECOVERY;
一方、次の文はRECOを使用可能にし、インダウト・トランザクションが自動的に解決されるようにします。
ALTER SYSTEM ENABLE DISTRIBUTED RECOVERY;
Oracle Databaseの分散読込み一貫性の実装には、重要な制限事項があります。この問題は、各システムが独自のSCNを持っていることに起因します。SCNは、データベースの内部タイムスタンプとして表示できます。Oracle Databaseサーバーは、SCNを使用して、問合せにどのバージョンのデータを返せばよいかを判断します。
分散トランザクションのSCNは、リモートSQL文の最後と、各トランザクションの最初および最後で同期化されます。2つのノード間の通信量が多く、特に分散更新がある場合には、この同期化が頻繁に実行されます。しかし、分散システムのSCNの絶対的な同期を保つための実用的な手段は存在しません。つまり、あるノードのSCNが別のノードのSCNと比べて幾分古くなるというような状況が常に存在します。
このようなSCNの食い違いから、実行した問合せがわずかに古いスナップショットを使用する可能性があります。その問合せ結果には、リモート・データベースに対する最新の変更が含まれていません。そのため、問合せを実行したときに、読込み一貫性に従ってデータが取得されているにもかからわず、そのデータが古い場合があります。そのような問合せによって取得したデータは、すべて古いSCNに基づいています。したがって、ローカルに実行した更新トランザクションによってリモート・ノードの2つの表が更新された場合、次回のリモート・アクセスで両方の表から選択したデータには、更新前のデータが含まれることになります。
SCNが食い違っているために起こりうる結果の1つとして、SELECT
文が2つ連続している場合に、それら2つの文の間でDMLをまったく実行していなくても各文で異なるデータが取得されることがあります。たとえば、UPDATE文を発行して、リモート・データベースで更新をコミットしたとします。このリモート表に基づくビューに対してSELECT
文を発行すると、ビューには更新された行が表示されません。次にSELECT
文を発行するときは、更新された行が表示されます。
次の手法を使用すると、問合せの直前に2つのマシンのSCNが必ず同期化されます。
SELECT * FROM DUAL@REMOTE
というようなダミーのリモート問合せを実行します。