次の例ではデッドロック状態を示しています。
テーブル定義
次のテーブル定義があるとします。
CREATE TABLE table_1 ( column_1 INTEGER, column_2 INTEGER, column_3 INTEGER, column_4 INTEGER) PRIMARY INDEX (column_1);
次の2つのトランザクションが並列に実行されています。
トランザクション 番号 |
リクエスト 番号 |
SQLテキスト |
---|---|---|
1 | 1 | LOCKING table_1 FOR READ CREATE INDEX (column_3, column_4) ON table_1; |
2 | 2 | BEGIN TRANSACTION; |
3 | SELECT * FROM table_1; |
|
4 | UPDATE table_1 SET column_1 = <value-1> WHERE column_1 = <value-2>; |
|
5 | END TRANSACTION; |
問題のトランザクション
トランザクション内のアクションが、以下の順序で実行されることを想定します。
- トランザクション1は、table_1にREADロックを設定します。
このロックは、テーブル ヘッダーに変更が必要になるまで(インデックス サブテーブルの作成の完了後まで)有効です。
- リクエスト3は、table_1にREADロックを設定します。
- トランザクション1とリクエスト3は、table_1にアクセスできるようになったときに並行して実行できるようになります。
- リクエスト3は終了していますが、トランザクションの終わりまでtable_1のREADロックを解放しません。
- リクエスト4は、table_1にWRITE行ハッシュ レベルのロックを設定しようとします。
table_1にはトランザクション1によってREADロックが設定されているため、そのロック リクエストはブロックされます。
- トランザクション1は、自体のロックをREADからEXCLUSIVEに格上げする必要があります。
トランザクション2のリクエスト4によってWRITE行ハッシュ レベル ロックが設定されているため、そのロック リクエストはブロックされます。
- この時点で、デッドロック状態が発生します。トランザクション2のリクエスト4はトランザクション1がそのロックを解放するのを待ち、トランザクション1はリクエスト4によってブロックされています。
問題の解決
このデッドロックを回避するには、次のいずれかの方法でSQLを変更してください。
- 次に示すように、トランザクション2に修飾子LOCKING table_1 FOR WRITEを追加します。
LOCKING table_1 FOR WRITE BEGIN TRANSACTION; SELECT * FROM table_1; UPDATE table_1 SET column_1 = value_1 WHERE column_1 = value_2; END TRANSACTION;
- トランザクション1からLOCKINGリクエスト修飾子を削除する。
CREATE INDEX (column_3, column_4) ON table_1;