症状
MySQLで Deadlock found when trying to get lock; try restarting transaction エラーが発生する
結論:まずこれを確認
SHOW ENGINE INNODB STATUSでデッドロックの詳細を確認する- 直近のデッドロック情報から、競合しているトランザクションを特定する
- アプリケーション側でリトライ処理が実装されているか確認する
トラブルシューティングフロー
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 条件"
🔍 チェックポイント: type が ALL(フルスキャン)になっていないか確認する
ステップ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が即座に検出してロールバックするため、このパラメータは直接関係しない。
関連するエラー・症状
準備中
解決しない場合
- MySQL公式ドキュメント - デッドロック
- 確認すべきログ: MySQLエラーログ(
innodb_print_all_deadlocks有効化後) - 次に調べるキーワード:
innodb gap lock,innodb lock mode,トランザクション分離レベル