次のMySQL UPDATE
ステートメントを実行しています。
mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
トランザクションを使用していないのに、なぜこのエラーが発生するのですか?MySQLサーバーの再起動を試みただけで解決しませんでした。
テーブルには406,733行あります。
次のMySQL UPDATE
ステートメントを実行しています。
mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
トランザクションを使用していないのに、なぜこのエラーが発生するのですか?MySQLサーバーの再起動を試みただけで解決しませんでした。
テーブルには406,733行あります。
回答:
トランザクションを使用しています。自動コミットはトランザクションを無効にするのではなく、ステートメントの最後で自動的にコミットさせるだけです。
何が起こっているのですか?他のスレッドがレコードのレコードロックを長時間保持し(テーブルのすべてのレコードを更新しています!)、スレッドがタイムアウトしています。
イベントの詳細を表示するには、
SHOW ENGINE INNODB STATUS
イベント後(sql
エディター内)。理想的には、静かなテストマシンでこれを行います。
process
アイドルになるまで待機する必要があります)。その場合、このエラーが発生する可能性があります。私は正しいですか?
connection.commit()
している場合は、コミットするために使用するINSERT
か、UPDATE
先ほど通りました。
MySQLでロックされたテーブルのUNLOCKを強制する方法:
このようにロックを解除すると、ロックを引き起こしたSQLステートメントにデータベースのアトミック性が適用されなくなります。
これはハッカであり、適切な解決策は、ロックを引き起こしたアプリケーションを修正することです。しかし、ドルが線上にある場合、迅速なキックは物事を再び動かすでしょう。
1)MySQLに入る
mysql -u your_user -p
2)ロックされたテーブルのリストを見てみましょう
mysql> show open tables where in_use>0;
3)現在のプロセスのリストを見てみましょう。それらの1つはテーブルをロックしています。
mysql> show processlist;
4)これらのプロセスの1つを強制終了します
mysql> kill <put_process_id_here>;
mysql> set innodb_lock_wait_timeout=100
Query OK, 0 rows affected (0.02 sec)
mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100 |
+--------------------------+-------+
ここで再びロックをトリガーします。SHOW ENGINE INNODB STATUS\G
データベースにを発行して、他のトランザクションがロックしているトランザクションを確認するための100秒の時間があります。
データベースが微調整されているかどうかを確認してください。特にトランザクションの分離。innodb_lock_wait_timeout変数を増やすことはお勧めできません。
mysql cliでデータベーストランザクション分離レベルを確認します。
mysql> SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation, @@session.transaction_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ | REPEATABLE-READ | REPEATABLE-READ |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)
分離レベルを変更することで改善を得ることができ、REPEATABLE READ(InnoDBデフォルト)の代わりにREAD COMMITTEDのようなOracleを使用します。
mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql>
また、必要な場合にのみSELECT FOR UPDATEを使用してみてください。
tx_isolation
変数の名前をに変更しましたtransaction_isolation
。
提案された解決策はどれもうまくいきませんでしたが、これはうまくいきました。
何かがクエリの実行をブロックしています。おそらく、クエリ内のテーブルの1つから更新、挿入、または削除している別のクエリです。あなたはそれが何であるかを知る必要があります:
SHOW PROCESSLIST;
ブロッキングプロセスを見つけたら、それid
を見つけて実行します。
KILL {id};
最初のクエリを再実行します。
このテーブル内の他のレコードを更新できますか、またはこのテーブルは頻繁に使用されていますか?私が考えているのは、このレコードを更新する必要があるロックを取得しようとしているときに、設定されたタイムアウトがタイムアウトしたことです。あなたは助けるかもしれない時間を増やすことができるかもしれません。
innodb_lock_wait_timeout
中my.cnf
行数は膨大ではありません...主キーでない場合は、account_import_idにインデックスを作成してください。
CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);
大きなクエリを終了したばかりの場合は、まで時間がかかりますrollback
。強制終了されたクエリがロールバックされる前に別のクエリを発行すると、ロックタイムアウトエラーが発生する可能性があります。それが私に起こったことです。解決策は少し待つことでした。
詳細:
DELETEクエリを発行して、約100万行から約90万行を削除しました。
私は誤ってこれを実行しました(行の10%のみを削除します):
DELETE FROM table WHERE MOD(id,10) = 0
これの代わりに(行の90%を削除します):
DELETE FROM table WHERE MOD(id,10) != 0
10%ではなく、90%の行を削除したかったのです。そのため、これまでに削除したすべての行をロールバックすることがわかっているため、MySQLコマンドラインでプロセスを強制終了しました。
その後、すぐに正しいコマンドを実行しましたが、lock timeout exceeded
すぐにエラーが発生しました。ロックはrollback
、バックグラウンドでまだ発生している強制終了されたクエリのロックである可能性があることに気付きました。そのため、数秒待ってクエリを再実行しました。
データベーステーブルがInnoDBストレージエンジンとREAD-COMMITTEDトランザクション分離レベルを使用していることを確認してください。
SELECT @@ GLOBAL.tx_isolation、@@ tx_isolation;で確認できます。mysqlコンソール上。
READ-COMMITTEDに設定されていない場合は、設定する必要があります。設定する前に、mysqlでSUPER権限を持っていることを確認してください。
http://dev.mysql.com/doc/refman/5.0/en/set-transaction.htmlからサポートを受けることができます。
これを設定することであなたの問題は解決されると思います。
また、これを2つのプロセスで一度に更新しようとしていないことを確認することもできます。ユーザー(@tala)は、このコンテキストで同様のエラーメッセージに遭遇しました。おそらくそれを再確認してください...
私はGoogleから来ましたが、自分に合ったソリューションを追加したかっただけです。私の問題は、カスケードに多数のFKがある巨大なテーブルのレコードを削除しようとしていたため、OPと同じエラーが発生したことです。
私は無効にautocommit
した後COMMIT
、SQL文の最後に追加するだけで機能しました。私が理解している限り、これはコマンドの最後で待機するのではなく、少しずつバッファを解放します。
OPの例を維持するには、これでうまくいくはずです。
mysql> set autocommit=0;
mysql> update customer set account_import_id = 1; commit;
autocommit
以前のようにMySQL構成を残したい場合は、再度アクティブ化することを忘れないでください。
mysql> set autocommit=1;
私のインスタンスでは、データを修正するために異常なクエリを実行していました。 クエリでテーブルをロックする場合、ロックタイムアウトを処理する必要はありません。
LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;
これは通常の使用にはおそらくお勧めできません。
詳細については、MySQL 8.0リファレンスマニュアルを参照してください。
私はこれを2つのDoctrine DBAL接続に遭遇しました。そのうちの1つは非トランザクション(重要なログ用)であり、相互に依存せずに並列実行することを目的としています。
CodeExecution(
TransactionConnectionQuery()
TransactionlessConnectionQuery()
)
私の統合テストは、非常にテストの後で、データのロールバックのためにトランザクションにラップされました。
beginTransaction()
CodeExecution(
TransactionConnectionQuery()
TransactionlessConnectionQuery() // CONFLICT
)
rollBack()
私の解決策は、これらのテストでラッピングトランザクションを無効にし、別の方法でデータベースデータをリセットすることでした。