ORA-02049: timeout: distributed transaction waiting for lock は、Oracleの分散トランザクションでロック待ちが長引き、distributed_lock_timeout の秒数を超えた時に発生するエラーです。DBリンク経由で別DBの表を更新する処理、複数DBにまたがるCOMMIT、リモートDB側の未コミット更新が絡む処理で起きやすいです。
通常のロック待ちと違い、ローカルDBだけを見ても原因が見えないことがあります。ローカルDBで待っているセッション、DBリンク先でロックを持っているセッション、分散トランザクションの状態を分けて確認します。
ORA-02049が出たら、まず処理をROLLBACKして再試行できる状態に戻します。次に
v$session、v$lock、dba_2pc_pending、DBリンク先DBのセッションを確認します。distributed_lock_timeout を伸ばす前に、未コミットトランザクションやロック順序、DBリンク先の処理遅延を疑います。ORA-02049とは
Oracle公式のエラー説明では、ORA-02049は distributed_lock_timeout 初期化パラメータで指定された秒数を超えて、ロックまたは分散トランザクション開始時の競合解消を待った時に発生します。対処としては、デッドロックのように扱い、トランザクションをロールバックして再試行することが示されています。
つまり、ORA-02049は「単に待てばよい」ではなく、分散トランザクションのどこかでロックが解放されないまま時間切れになったサインです。DBリンクの基本は データベースリンク完全ガイド、COMMIT/ROLLBACKの考え方は Oracleトランザクション完全ガイド も参考になります。
よくある発生パターン
DBリンク経由のUPDATE/DELETE
ローカルDBから UPDATE remote_table@dblink を実行し、リモート側で同じ行が未コミット更新中のケースです。
複数DBにまたがる処理
ローカル表とリモート表を同一トランザクション内で更新し、どちらかのDBでロック待ちが長引くケースです。
COMMIT/ROLLBACK漏れ
アプリケーション、SQLツール、バッチが未コミットのまま放置され、別セッションがリモート側で待ち続けるケースです。
ロック取得順序の不一致
処理Aはローカル→リモート、処理Bはリモート→ローカルの順に更新するなど、分散環境で競合しやすい順序になっているケースです。
DBリンク先DBの遅延
リモートDB側の長時間SQL、待機イベント、ネットワーク遅延により、ロック解放や2フェーズコミット処理が遅れるケースです。
distributed_lock_timeoutを確認する
まず、現在の待機時間設定を確認します。ただし、この値を大きくすれば解決するとは限りません。原因が未コミット放置やロック順序なら、単に失敗までの時間が延びるだけです。
SHOW PARAMETER distributed_lock_timeout;
SELECT name,
value,
isdefault,
issys_modifiable
FROM v$parameter
WHERE name = 'distributed_lock_timeout';
distributed_lock_timeout を大きくすると、利用者から見る待ち時間も長くなります。障害時は先にロック元セッション、未コミット処理、DBリンク先の状態を確認します。どのDBリンクを使っているか確認する
ORA-02049では、まず対象のDBリンクと接続先DBを特定します。アプリケーションSQLに @DBLINK が見えていれば早いですが、セッション状態や DBA_DB_LINKS のDBリンク定義から確認できることもあります。
SELECT db_link,
owner_id,
logged_on,
heterogeneous,
protocol,
open_cursors,
in_transaction
FROM v$dblink
ORDER BY db_link;
SELECT owner,
db_link,
username,
host,
created
FROM dba_db_links
WHERE db_link LIKE UPPER('%TARGET%')
ORDER BY owner, db_link;
V$DBLINK.IN_TRANSACTION が YES の場合、そのセッションがDBリンクを使ったトランザクション中である可能性があります。接続先の HOST やDBリンク名から、どのリモートDBを調査するかを決めます。
ローカルDB側の待機セッションを確認する
ORA-02049が出たセッションの周辺で、ローカルDB側に待機やブロッキング情報が残っていないか確認します。blocking_session が取れない場合もありますが、イベント、SQL ID、DBリンクを使うSQLを確認します。
SELECT sid,
serial#,
username,
machine,
program,
status,
event,
blocking_session,
seconds_in_wait,
sql_id
FROM v$session
WHERE username IS NOT NULL
ORDER BY seconds_in_wait DESC;
SELECT s.sid,
s.serial#,
s.username,
s.sql_id,
q.sql_text
FROM v$session s
JOIN v$sql q
ON q.sql_id = s.sql_id
WHERE q.sql_text LIKE '%@%'
ORDER BY s.sid;
通常のセッション確認や強制切断の基本は セッションの確認・強制切断方法 も参考になります。
ロック情報を確認する
ローカルDB側で見える範囲のロックを確認します。分散トランザクションではリモートDB側のロックが本体のこともあるため、このSQLだけで完結しない点に注意します。
SELECT s.sid,
s.serial#,
s.username,
s.machine,
s.program,
l.type,
l.id1,
l.id2,
l.lmode,
l.request,
l.block
FROM v$lock l
JOIN v$session s
ON s.sid = l.sid
WHERE l.request > 0 OR l.block > 0
ORDER BY l.block DESC, s.sid;
通常のロック待ち、DDLロック、デッドロックとの違いも見ます。ORA-00054、ORA-00060、ORA-04021 の記事も切り分けに使えます。
DBリンク先のセッションを確認する
ORA-02049では、DBリンク先DBでロックを持っているセッションを確認することが重要です。ローカルDBだけで原因が分からない場合、リモートDBへログインして同じ時間帯のセッション、SQL、ロックを確認します。
-- DBリンク先DBで実行する
SELECT sid,
serial#,
username,
machine,
program,
module,
status,
event,
blocking_session,
last_call_et,
sql_id
FROM v$session
WHERE username IS NOT NULL
ORDER BY last_call_et DESC;
-- DBリンク先DBで実行する
SELECT s.sid,
s.serial#,
s.username,
s.machine,
s.program,
o.owner,
o.object_name,
o.object_type,
lo.locked_mode
FROM v$locked_object lo
JOIN dba_objects o
ON o.object_id = lo.object_id
JOIN v$session s
ON s.sid = lo.session_id
ORDER BY s.last_call_et DESC;
リモート側で未コミットの更新セッションが見つかった場合、業務影響を確認してCOMMIT/ROLLBACK、ジョブ停止、またはセッション整理を検討します。
分散トランザクションの未解決状態を確認する
ネットワーク断や障害が絡むと、分散トランザクションが未解決の状態として残ることがあります。DBA_2PC_PENDING でin-doubtトランザクションの有無を確認します。
SELECT local_tran_id,
global_tran_id,
state,
mixed,
advice,
tran_comment,
fail_time,
force_time,
retry_time
FROM dba_2pc_pending
ORDER BY fail_time DESC;
SELECT local_tran_id,
in_out,
database,
dbuser_owner,
interface
FROM dba_2pc_neighbors
ORDER BY local_tran_id, in_out;
SELECT p.local_tran_id,
p.state,
p.mixed,
p.fail_time,
n.in_out,
n.database,
n.dbuser_owner,
n.interface
FROM dba_2pc_pending p
LEFT JOIN dba_2pc_neighbors n
ON n.local_tran_id = p.local_tran_id
ORDER BY p.fail_time DESC, n.in_out;
COMMIT FORCE や ROLLBACK FORCE は、分散トランザクションの整合性に関わる操作です。実行前に関係DBの状態、業務影響、トランザクションの状態、Oracleサポートや運用手順を確認します。-- 例: 運用手順で明確に判断できる場合だけ実行する -- COMMIT FORCE 'local_tran_id'; -- ROLLBACK FORCE 'local_tran_id'; -- 実行後はDBA_2PC_PENDINGで状態を再確認する SELECT local_tran_id, state, mixed, force_time FROM dba_2pc_pending ORDER BY fail_time DESC;
再試行設計を入れる
Oracle公式でも、ORA-02049はデッドロックのように扱い、トランザクションをロールバックして再試行する方針が示されています。アプリケーション側では、同じトランザクションを握ったまま再実行するのではなく、一度ROLLBACKしてから短い待機を挟んで再試行します。
ORA-02049発生時の考え方 1. 現在のトランザクションをROLLBACKする 2. 短い待機を入れる 3. 同じ処理を再試行する 4. 再試行回数を超えたら業務エラーとして扱う 5. ログにローカルDB、DBリンク名、SQL ID、対象キーを残す
再試行しても頻発する場合は、処理順序、更新対象キー、DBリンク先の長時間トランザクション、接続プールやバッチ多重起動を見直します。
ロック順序をそろえる
分散トランザクションでは、複数の処理が別々の順序でローカル表とリモート表を更新すると、ロック待ちが起きやすくなります。可能なら、すべての処理でロック取得順序をそろえます。
悪い例: 処理A: ローカル表 -> リモート表@DBLINK 処理B: リモート表@DBLINK -> ローカル表 改善例: 処理A: ローカル表 -> リモート表@DBLINK 処理B: ローカル表 -> リモート表@DBLINK 同じ順序でロックを取ることで、相互待ちやタイムアウトを減らす。
関連エラーとの違い
ORA-02049
分散トランザクションでロック待ちが distributed_lock_timeout を超えたエラーです。DBリンク先DBの確認が重要です。
ORA-00054
NOWAIT指定やDDL_LOCK_TIMEOUTに関連するロック取得失敗です。主にローカルDBのDDLやリソース待ちで見ます。
ORA-00060
デッドロックです。複数セッションが互いのロック解放を待ち、Oracleが検出して片方を失敗させます。
ORA-04021
DDLやコンパイルでオブジェクトロックを取得できずタイムアウトするエラーです。ライブラリキャッシュやDDLロック待ちを見ます。
ORA-02050 / ORA-02068
分散トランザクションやDBリンク先の障害で一緒に確認することがあります。ローカルDBだけでなくリモートDB側のログも見ます。
対応手順のまとめ
- ORA-02049が出た処理をROLLBACKし、再試行可能な状態に戻す
distributed_lock_timeoutの現在値を確認するV$DBLINKとDBリンク定義で、対象DBリンクと接続先DBを特定する- ローカルDB側の
v$session、v$lock、SQL IDを確認する - DBリンク先DBにログインして、リモート側のセッションとロックを確認する
DBA_2PC_PENDINGで未解決の分散トランザクションを確認する- 未コミット放置、長時間SQL、ロック順序、バッチ多重起動を見直す
- アプリケーション側にROLLBACK後の再試行設計を入れる
よくある質問
distributed_lock_timeoutを伸ばせば直りますか?
一時的にエラーが出にくくなる可能性はありますが、根本対策ではありません。未コミット処理やDBリンク先のロックが原因なら、待ち時間が延びるだけです。
ローカルDBにロック元が見つかりません。
DBリンク先DBでロックを持っている可能性があります。リモートDBへログインし、同じ時間帯の v$session、v$locked_object、実行SQLを確認します。
ORA-02049はデッドロックですか?
厳密にはORA-00060とは別のエラーですが、Oracle公式ではデッドロックのように扱い、ROLLBACKして再試行する対処が示されています。
COMMIT FORCEを使ってよいですか?
安易に使いません。in-doubtトランザクションの強制解決は整合性に影響します。関係DBの状態と運用手順を確認してから判断します。
ORA-02050やORA-02068も出ています。何を見ますか?
分散トランザクションやDBリンク先の障害が絡んでいる可能性があります。ローカルDBのエラーだけでなく、DBリンク先DBのアラートログ、セッション、未解決トランザクションを確認します。

