web-dev-qa-db-ja.com

トランザクションを使用していなくても、「ロック待機タイムアウトを超えました。トランザクションを再開してみてください」というメッセージが表示される

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

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

トランザクションを使用していないのですが、なぜこのエラーが発生するのでしょうか。私は自分のMySQLサーバを再起動しようとさえしました、そして、それは助けになりませんでした。

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

209
Jason Swett

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

何が起きているかというと、他のスレッドがあるレコードに対してレコードロックを長時間保持していて(テーブルのすべてのレコードを更新しているのです)、スレッドはタイムアウトしています。

あなたが発行することによってイベントの詳細を見ることができます

SHOW ENGINE INNODB STATUS

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

176
MarkR

MySQLでロックされたテーブルのロックを解除する方法:

このようにロックを解除すると、データベース内で アトミック性 がロックを引き起こしたsqlステートメントに適用されないことがあります。

これは厄介です、そして適切な解決策はロックを引き起こしたあなたのアプリケーションを修正することです。しかし、ドルが並んでいるとき、Swiftのキックは物事を再び動かすでしょう。

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>;
265
Eric Leschinski
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秒の時間があります。

81
veen

データベースが微調整されているかどうかを確認してください。特にトランザクションの分離innodb_lock_wait_timeout変数を増やすことはお勧めできません。

Mysqlのcliでデータベースのトランザクション分離レベルを確認します。

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)

分離レベルを変更することで改善を得ることができます。代わりにOracleのREAD COMMITTEDを使用してください。

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も使用してください。

62
saisyukusanagi

提案された解決策のどれも私のために働きませんでしたが、これは働きました。

何かがクエリの実行をブロックしています。ほとんどの場合、別のクエリがクエリ内のいずれかのテーブルを更新、挿入、または削除しています。あなたはそれが何であるかを知る必要があります。

SHOW PROCESSLIST;

ブロックしているプロセスを見つけたら、そのidを見つけて実行します。

KILL {id};

最初のクエリを再実行してください。

15
BassMHL

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

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

12
James C

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

5
John Kane

行数はそれほど大きくありません... account_import_idが主キーでない場合は、account_import_idにインデックスを作成します。

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);
1
gladiator

データベーステーブルが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
Ravi Chhatrala

このようなことは私がphp言語の構成要素出口を使用していたときに私に起こりました。取引中です。それからこのトランザクションは「ハング」します、そしてあなたはmysqlプロセスを殺す必要があります(processlistで上で説明された)

0
TomoMiha

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

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

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

より詳しい情報は: MySQL 8.0リファレンスマニュアル

0
Jeff Luyet

パーティーに遅刻して(いつものように)しかし私の問題は私がいくつかの悪いSQLを書いたこと(初心者である)といくつかのプロセスがレコードをロックしていたという事実でした。私はSHOW PROCESSLISTをしてからKILL <id>を使ってIDを削除するだけで済みました。

0
Smitty

私はこれに遭遇しました2つのDoctrine DBAL接続、そのうちの1つは(重要なログのために)非トランザクションとして、それらは互いに依存しないで並行して実行することを意図しています。

CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery()
)

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

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

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

0
Fabian Picone

大きなクエリを殺したばかりの場合は、rollbackに時間がかかります。強制終了されたクエリがロールバックされる前に別のクエリを発行すると、ロックタイムアウトエラーが発生する可能性があります。それが私に起こったことです。解決策は少し待つことでした。

詳細:

私はDELETEクエリを発行して、約100万行から約900,000行を削除しました。

これを誤って実行しました(行の10%のみを削除します)。DELETE FROM table WHERE MOD(id,10) = 0

これの代わりに(行の90%を削除します):DELETE FROM table WHERE MOD(id,10) != 0

10%ではなく、90%の行を削除したいと思いました。そのため、これまでに削除したすべての行をロールバックすることになるので、MySQLコマンドラインでプロセスを強制終了しました。

それから私はすぐに正しいコマンドを実行し、そしてすぐにlock timeout exceededエラーを受け取りました。ロックは実際にはバックグラウンドで行われているkillされたクエリのrollbackである可能性があることに気付きました。そこで数秒待ってからクエリを再実行しました。

0
Buttle Butkus

私はグーグルから来ました、そして、私はちょうど私のために働いた解決策を加えたかったです。私の問題は、カスケード状態でFKが多い巨大なテーブルのレコードを削除しようとしていたため、OPと同じエラーが発生したことです。

私はautocommitを無効にしてから、SQL文の最後にCOMMITを追加するだけでうまくいきました。私が理解している限りでは、これはコマンドの終わりで待つ代わりに少しずつバッファを解放します。

OPの例を続けるには、これでうまくいくはずです。

mysql> set autocommit=0;

mysql> update customer set account_import_id = 1; commit;

以前のようにMySQLの設定を終了したい場合は、autocommitを再度アクティブにすることを忘れないでください。

mysql> set autocommit=1;

0
Kamae