「ロック待機タイムアウトを超えました。トランザクションを使用していないにもかかわらず、トランザクションを再開してみてください」


267

次のMySQL UPDATEステートメントを実行しています。

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

トランザクションを使用していないのに、なぜこのエラーが発生するのですか?MySQLサーバーの再起動を試みただけで解決しませんでした。

テーブルには406,733行あります。

回答:


211

トランザクションを使用しています。自動コミットはトランザクションを無効にするのではなく、ステートメントの最後で自動的にコミットさせるだけです。

何が起こっているのですか?他のスレッドがレコードのレコードロックを長時間保持し(テーブルのすべてのレコードを更新しています!)、スレッドがタイムアウトしています。

イベントの詳細を表示するには、

SHOW ENGINE INNODB STATUS

イベント後(sqlエディター内)。理想的には、静かなテストマシンでこれを行います。


1
出力をファイルに保存する方法はありますか?SHOW ENGINE INNODB STATUS \ G> innodb_stat.txtを試しましたが、機能しません。
yantaq 2015

14
コマンドラインから:mysql [資格情報を挿入] -e "SHOW ENGINE INNODB STATUS \ G"> innodb_stat.txt
VenerableAgents

多くのmysqlスレッド(またはプロセス)がビジーである場合(たとえば、一部のクエリは非常に長い時間を必要とするため、processアイドルになるまで待機する必要があります)。その場合、このエラーが発生する可能性があります。私は正しいですか?
zhuguowei

6
単一のトランザクション中に同じ行で複数の(2+)UPDATEクエリを実行すると、このエラーも発生します。
Okneloper 2018

Python MySQL Connectorを使用connection.commit()している場合は、コミットするために使用するINSERTか、UPDATE先ほど通りました。
AER

334

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>;

14
これは危険でハックです。適切な解決策は、アプリケーションを修正することです。
Zenexer 2015

71
ナンセンスです。これにより、混乱を元に戻してアプリケーションを修正できます。もしこの男にこの問題に対して100票を投じることができれば、今修正しなければならなかったとしたら。
Lizardx 2016年

7
私はLizardxに同意します。これは、SHOW ENGINE INNODB STATUS
Travis Schneeberger

8
この方法で長時間実行されているクエリを強制終了すると、どのように危険ですか?クライアントの呼び出しはエラーになります。
Xeoncross 2018

7
@EricLeschinski私はあなたのポイントを得るが、私は世界にあなたのようなずさんなデータベースを使用する理由聞いているのMySQLライフクリティカルシステムを?
-Xeoncross

96
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秒の時間があります。


8
この回答は、質問者がエラーを取得する理由を説明していません。答えを出すだけでなく、理由を詳しく説明してください。
そり

5
これは質問に直接答えるものではありませんが、+ 1は、私にとってはこの問題の回避策への良い参考になります。
Jossef Harush、2016

1
@ ArtBdev.mysql.com / doc / innodb / 1.1 / en / 本質的に、テーブルでロックが呼び出され、トランザクションを終了するまでの経過時間がlock_wait_timeout値を超えたため、OPはエラーを受信して​​います
fyrye

70

データベースが微調整されているかどうかを確認してください。特にトランザクションの分離。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を使用してみてください。


1
これは、ロックの問題に対する優れたソリューションです。
2014

3
my.cnfバージョンは[mysqld]です。トランザクション分離= READ-COMMITTED
Benoit Gauthier

注意:MySQL 8はtx_isolation変数の名前をに変更しましたtransaction_isolation
xonya

ただし、read-isolationからREAD COMMITTEDに変更する場合は、何を取得するのか注意する必要があります。あなたはあなたが避けたいと思うかもしれない汚いデータで終わるかもしれません。ウィキペディアIsoloation
ハギー

27

提案された解決策はどれもうまくいきませんでしたが、これはうまくいきました。

何かがクエリの実行をブロックしています。おそらく、クエリ内のテーブルの1つから更新、挿入、または削除している別のクエリです。あなたはそれが何であるかを知る必要があります:

SHOW PROCESSLIST;

ブロッキングプロセスを見つけたら、それidを見つけて実行します。

KILL {id};

最初のクエリを再実行します。


SHOW PROCESSLISTでリストされたすべてのプロセスを誤って強制終了しました。現在、phpmyadminで500エラーが発生しています。これらの500エラーは、これらのプロセスの強制終了に関連していますか?はいの場合、どうすれば再起動できますか。
Dashrath、2016年

私はあなたの説明を見ることができますが、プロセスを殺すことはうまくいきません。プロセスのコマンドは「強制終了」されますが、プロセスリストには残ります。
Torsten

12

MarkRが言ったことを100%。自動コミットは、各ステートメントを1つのステートメントトランザクションにします。

SHOW ENGINE INNODB STATUSデッドロックの理由についていくつかの手掛かりを与えるはずです。遅いクエリログもよく見て、他に何がテーブルをクエリしているかを確認し、フルテーブルスキャンを実行しているものをすべて削除してみてください。行レベルのロックは適切に機能しますが、すべての行をロックしようとしている場合は機能しません。


5

このテーブル内の他のレコードを更新できますか、またはこのテーブルは頻繁に使用されていますか?私が考えているのは、このレコードを更新する必要があるロックを取得しようとしているときに、設定されたタイムアウトがタイムアウトしたことです。あなたは助けるかもしれない時間を増やすことができるかもしれません。


3
多分innodb_lock_wait_timeoutmy.cnf
oblig

1
my.cnfで設定しました。<br/> innodb_lock_wait_timeout = 120 <br/> mysql 5.5のデフォルトは50です。この変更後、ユニットテストでこの問題を確認できませんでした。これは、proxoolからtomcat jdbcプールに切り替えた後に発生しました。おそらくTomcatプールでのトランザクション時間が長いためでしょうか?
Champ

3

行数は膨大ではありません...主キーでない場合は、account_import_idにインデックスを作成してください。

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);

OMG ...これは私を救っただけです。私はインデックスを削除することで本番DBを忠実にねじ込み、これを修正しました。ありがとうございます。
Nick Gotch

2

大きなクエリを終了したばかりの場合は、まで時間がかかります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、バックグラウンドでまだ発生している強制終了されたクエリのロックである可能性があることに気付きました。そのため、数秒待ってクエリを再実行しました。


1

データベーステーブルが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)は、このコンテキストで同様のエラーメッセージに遭遇しました。おそらくそれを再確認してください...


1

私は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;


0

パーティーの後期(いつものように)ですが、私の問題は、私がいくつかの悪いSQL(初心者)を作成し、いくつかのプロセスがレコードをロックしているという事実でした<-適切な表現がわからない。私はただしなければならなくなった:SHOW PROCESSLISTそしてそれからIDを殺すKILL <id>


0

私がphp言語の構造体出口を使用していたときに、このようなことが起こりました。トランザクションの途中。次に、このトランザクションは「ハング」し、mysqlプロセスを停止する必要があります(processlistを使用して上記で説明)。


0

私のインスタンスでは、データを修正するために異常なクエリを実行していました。 クエリでテーブルをロックする場合、ロックタイムアウトを処理する必要はありません。

LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;

これは通常の使用にはおそらくお勧めできません。

詳細については、MySQL 8.0リファレンスマニュアルを参照してください。


0

私はこれを2つのDoctrine DBAL接続に遭遇しました。そのうちの1つは非トランザクション(重要なログ用)であり、相互に依存せずに並列実行することを目的としています。

CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery()
)

私の統合テストは、非常にテストの後で、データのロールバックのためにトランザクションにラップされました。

beginTransaction()
CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery() // CONFLICT
)
rollBack()

私の解決策は、これらのテストでラッピングトランザクションを無効にし、別の方法でデータベースデータをリセットすることでした。


-4

これと同じエラーが発生しましたが、1つのテーブルで1つのエントリしか更新していませんでしたが、mysqlを再起動すると解決しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.