並列処理が牙をむく時 - _high Oracle Autonomous DB (OCI)でのORA-12860

著者
Damian
Terlecki
1分間の読書
データベース

最近、OCI上のOracle Autonomous Databaseを使って小さなアプリのプロトタイプを作成していました。深く考えずに、最初に見つけた_highというサービス名を選んでしまいました。 この先に待ち受けるトラブルも知らずに。だって、"_high"は"_low"より響きがいいじゃないですか?

しばらくして、特に同じトランザクション内でテーブルからレコードを削除して再挿入する際に、奇妙な動作に気づき始めました。

テーブルはシンプルなものでした:

CREATE TABLE foo (
    bar_id      VARCHAR2(255) PRIMARY KEY,
    bar_user_id VARCHAR2(255) NOT NULL,
    bar_content VARCHAR2(2000)
);

そこにいくつかのレコードがあり、それらを削除して、古いものと新しいものの両方を再挿入しようとしていました:

DELETE FROM foo WHERE bar_user_id = 'some_user_id';

INSERT INTO foo (bar_id, bar_user_id, bar_content) VALUES ('old_id_1', 'some_user_id', 'new_content');
INSERT INTO foo (bar_id, bar_user_id, bar_content) VALUES ('old_id_2', 'some_user_id', 'new_content');
-- ...さらにINSERTが続く

すると突然、こんなエラーが:

ORA-12860: deadlock detected while waiting for a sibling row lock

こんな単純な操作で、まさかこんなエラーが出るとは思いませんでした。

テーブルの設定、インデックス、トリガーを確認しましたが、何も目立ったものはありませんでした。 その時、ふと思い出しました。DBサービスが異なるワークロードに最適化されているという話を。 実際の問題は、_highサービスを使用する際のセッションの並列処理レベルでした。DBAアカウントからgv$px_sessionをさっと確認したところ、degreeの値が1より大きいことが確定しました。

v$sessionv$transactionsaddrで結合すると、すぐに詳細がわかりました。 最初のDELETE文が4つの並列スレーブを生成していました。 そして、その後、以前に削除した行をINSERTしようとしたときに、同じトランザクション内で内部的なデッドロックが発生していたのです。

驚くことではありませんが、並列処理を無効にする_lowサービス名に切り替えたところ、問題は解決しました。

もしあなたが同様のケースでORA-12860エラーに遭遇し、この記事を見つけたなら、この簡単な説明が少しでもあなたの頭を悩ませる時間を節約できれば幸いです。 この記事を書いている時点では、このエラーの検索結果はあまり役に立ちませんでした。

詳細はOCI Oracle Autonomous Databaseのサービス記述をご覧ください。