MySQL 8.0 リファレンスマニュアル


15.7.5 InnoDB のデッドロック

デッドロックとは、それぞれが他の必要なロックを保持しているために、異なるトランザクションを続行できない状況です。 両方のトランザクションがリソースが使用可能になるのを待機しているため、保持しているロックは解放されません。

デッドロックは、(UPDATESELECT ... FOR UPDATE などのステートメントを使用して) 複数のテーブルの行をトランザクションがロックするときに発生する可能性がありますが、逆の順序で発生します。 デッドロックは、このようなステートメントがインデックスレコードとギャップの範囲をロックし、各トランザクションが一部のロックを取得するけれども、タイミングの問題によりほかを取得しない場合にも発生することがあります。 デッドロックの例については、セクション15.7.5.1「InnoDB デッドロックの例」 を参照してください。

デッドロックの可能性を減らすには、LOCK TABLES ステートメントではなくトランザクションを使用します。データを挿入または更新するトランザクションのサイズは、長期間オープンしたままにしないでください。異なるトランザクションが複数のテーブルまたは行の範囲を更新する場合は、各トランザクションで同じ順序 (SELECT ... FOR UPDATE など) を使用し、SELECT ... FOR UPDATE ステートメントおよび UPDATE ... WHERE ステートメントで使用されるカラムにインデックスを作成します。 デッドロックの可能性は、分離レベルに影響を受けません。分離レベルは読み取り操作の動作を変更し、デッドロックは書き込み操作のために発生するからです。 デッドロック状態からの回避およびリカバリの詳細は、セクション15.7.5.3「デッドロックを最小化および処理する方法」 を参照してください。

デッドロック検出が有効 (デフォルト) でデッドロックが発生した場合、InnoDB は条件を検出し、いずれかのトランザクション (被害者) をロールバックします。 innodb_deadlock_detect 構成オプションを使用してデッドロック検出が無効になっている場合、InnoDB は、デッドロックの場合にトランザクションをロールバックするために innodb_lock_wait_timeout 設定に依存します。 したがって、アプリケーションロジックが正しい場合でも、トランザクションを再試行する必要があるケースを処理する必要があります。 InnoDB ユーザートランザクションの最後のデッドロックを表示するには、SHOW ENGINE INNODB STATUS コマンドを使用します。 デッドロックが頻繁に発生して、トランザクション構造やアプリケーションエラー処理に問題があるらしいと思われる場合は、mysqld エラーログにすべてのデッドロックに関する情報を出力するために、innodb_print_all_deadlocks 設定を有効にした状態で実行してください。 デッドロックが自動的に検出および処理される方法の詳細は、セクション15.7.5.2「デッドロック検出」 を参照してください。


関連キーワード:  InnoDB, テーブル, デッドロック, トランザクション, 構成, ロック, インデックス, 圧縮, スペース, ステートメント