MySQL: Lock wait timeout exceeded
MySQLでロック取得の待機時間がタイムアウトした場合のエラー原因と解決策
概要
トランザクションが他のトランザクションのロック解放を待機中にタイムアウトするエラーです。
エラーメッセージ
``` ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction ```
原因
- 長時間トランザクション: 他のトランザクションがロックを長時間保持
- 大量データの更新: 広範囲の行ロック
- インデックス不足: テーブルスキャンによる意図しないロック
- innodb_lock_wait_timeout設定が短すぎる
解決策
1. ロック状況を確認
```sql – 現在のロック状況 SELECT * FROM information_schema.innodb_locks;
– ロック待ちのトランザクション SELECT * FROM information_schema.innodb_lock_waits;
– 実行中のトランザクション SHOW ENGINE INNODB STATUS; ```
2. タイムアウト値を調整
```sql – 現在の設定確認 SHOW VARIABLES LIKE ‘innodb_lock_wait_timeout’;
– セッション単位で変更 SET innodb_lock_wait_timeout = 120;
– グローバル設定(my.cnf) – innodb_lock_wait_timeout = 120 ```
3. インデックスを追加
```sql – インデックスがない場合、全行ロックが発生 – 悪い例 UPDATE orders SET status = ‘shipped’ WHERE user_id = 100;
– user_idにインデックスを追加 ALTER TABLE orders ADD INDEX idx_user_id (user_id); ```
4. トランザクションを分割
```python
悪い例: 大量更新を1トランザクションで
with db.transaction(): db.execute(“UPDATE orders SET status = ‘archived’ WHERE created_at < ‘2024-01-01’”)
良い例: バッチ処理
while True: with db.transaction(): affected = db.execute(""" UPDATE orders SET status = ‘archived’ WHERE created_at < ‘2024-01-01’ AND status != ‘archived’ LIMIT 1000 “”") if affected == 0: break ```
よくある間違い
- タイムアウト値を極端に大きくする
- リトライロジックなしで処理
- 本番環境でインデックスなしのUPDATE
関連エラー
関連エラー
MySQL の他のエラー
この記事は役に立ちましたか?