症状

MySQLで Deadlock found when trying to get lock; try restarting transaction エラーが発生する

結論:まずこれを確認

  1. SHOW ENGINE INNODB STATUS でデッドロックの詳細を確認する
  2. 直近のデッドロック情報から、競合しているトランザクションを特定する
  3. アプリケーション側でリトライ処理が実装されているか確認する

トラブルシューティングフロー

    flowchart TD
    A[Deadlockエラー発生] --> B{頻度は?}
    B -->|まれに発生| C[アプリでリトライ実装]
    B -->|頻繁に発生| D[SHOW ENGINE INNODB STATUS]
    D --> E{競合箇所を特定}
    E --> F[インデックス不足?]
    E --> G[トランザクション長すぎ?]
    E --> H[ロック順序不統一?]
    F -->|Yes| I[インデックス追加]
    G -->|Yes| J[トランザクション分割]
    H -->|Yes| K[ロック順序を統一]
    C --> L[監視を継続]
    I --> L
    J --> L
    K --> L
  

よくある原因

  • インデックス不足 - フルテーブルスキャンにより広範囲のロックが発生している
  • トランザクションが長い - ロック保持時間が長く、競合が発生しやすい
  • ロック順序の不統一 - 複数トランザクションが異なる順序でリソースをロックしている
  • 同時実行数が多い - 並列処理による競合が増加している
  • ギャップロック - 存在しない行への挿入で意図しないロック範囲が発生している
  • 外部キー制約 - 親テーブルと子テーブルで同時に操作が発生している

確認手順

ステップ1: デッドロック情報を取得する

    mysql -u root -p -e "SHOW ENGINE INNODB STATUS\G" | grep -A 50 "LATEST DETECTED DEADLOCK"
  

🔍 チェックポイント: LATEST DETECTED DEADLOCK セクションにデッドロックの詳細が表示される

ステップ2: 競合しているトランザクションを確認する

出力から以下を確認する:

    *** (1) TRANSACTION:
TRANSACTION 12345, ACTIVE 0 sec
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:

*** (2) TRANSACTION:
TRANSACTION 12346, ACTIVE 0 sec
*** (2) HOLDS THE LOCK(S):
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
  

🔍 チェックポイント: どのテーブル・インデックスでロック競合が起きているか特定する

ステップ3: 該当クエリのインデックス使用状況を確認する

    mysql -u root -p -e "EXPLAIN SELECT * FROM テーブル名 WHERE 条件"
  

🔍 チェックポイント: typeALL(フルスキャン)になっていないか確認する

ステップ4: 現在のロック状況を確認する

    mysql -u root -p -e "SELECT * FROM performance_schema.data_locks"
  

MySQL 5.7以前の場合:

    mysql -u root -p -e "SELECT * FROM information_schema.innodb_locks"
  

🔍 チェックポイント: 異常に多いロックが発生していないか確認する

ステップ5: 実行中のトランザクションを確認する

    mysql -u root -p -e "SELECT * FROM information_schema.innodb_trx"
  

🔍 チェックポイント: trx_started が古いトランザクションが残っていないか確認する

ステップ6: デッドロック監視設定を有効化する

    mysql -u root -p -e "SET GLOBAL innodb_print_all_deadlocks = ON"
  

🔍 チェックポイント: 以降のデッドロックがエラーログに出力されるようになる

NG行動(やってはいけないこと)

  • トランザクション分離レベルを安易に下げる - データ不整合の原因になる
  • ロックタイムアウトを極端に短くする - 正常な処理まで失敗する可能性がある
  • デッドロック発生時にリトライせず即エラーにする - デッドロックは正常なDB動作であり、リトライで解決することが多い
  • 原因調査せずにインデックスを追加する - 不要なインデックスはINSERT/UPDATE性能を低下させる

よくある質問(FAQ)

Q1: デッドロックは異常事態なのか?

A: デッドロック自体はInnoDBの正常な動作。発生を完全に防ぐことは困難なため、アプリケーション側でリトライ処理を実装するのが標準的な対処法。

Q2: どのくらいの頻度なら問題視すべき?

A: 明確な基準はないが、同一クエリで1分間に複数回発生する場合は調査を検討する。まれな発生(1日数回程度)はリトライで対処可能。

Q3: innodb_lock_wait_timeout を変更すべき?

A: デッドロックとロック待ちタイムアウトは別の問題。デッドロックはMySQLが即座に検出してロールバックするため、このパラメータは直接関係しない。

関連するエラー・症状

準備中

解決しない場合