私の制作エラーログで私は時々見ます:
SQLSTATE [HY000]:一般エラー:1205ロック待機タイムアウトを超えました。トランザクションを再開してみてください
その時点でどのクエリがデータベースにアクセスしようとしているのかはわかっていますが、その時点でどのクエリにロックがかけられているかを調べる方法はありますか?
これをもたらすのは、Wordトランザクションです。ステートメントによって、クエリが1つ以上のInnoDBテーブル内の少なくとも1つの行を変更しようとしていたことは明らかです。
クエリを知っているので、アクセスされているすべてのテーブルが原因である可能性があります。
そこから、SHOW ENGINE INNODB STATUS\G
を実行することができるはずです。
あなたは影響を受けたテーブルを見ることができるはずです
あなたはあらゆる種類の追加のロック情報とミューテックス情報を取得します。
これは私のクライアントの1人からのサンプルです:
mysql> show engine innodb status\G
*************************** 1. row ***************************
Type: InnoDB
Name:
Status:
=====================================
110514 19:44:14 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 4 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 9014315, signal count 7805377
Mutex spin waits 0, rounds 11487096053, OS waits 7756855
RW-shared spins 722142, OS waits 211221; RW-excl spins 787046, OS waits 39353
------------------------
LATEST FOREIGN KEY ERROR
------------------------
110507 21:41:35 Transaction:
TRANSACTION 0 606162814, ACTIVE 0 sec, process no 29956, OS thread id 1223895360 updating or deleting, thread declared inside InnoDB 499
mysql tables in use 1, locked 1
14 lock struct(s), heap size 3024, 8 row lock(s), undo log entries 1
MySQL thread id 3686635, query id 124164167 10.64.89.145 viget updating
DELETE FROM file WHERE file_id in ('6dbafa39-7f00-0001-51f2-412a450be5cc' )
Foreign key constraint fails for table `backoffice`.`attachment`:
,
CONSTRAINT `attachment_ibfk_2` FOREIGN KEY (`file_id`) REFERENCES `file` (`file_id`)
Trying to delete or update in parent table, in index `PRIMARY` Tuple:
DATA Tuple: 17 fields;
0: len 36; hex 36646261666133392d376630302d303030312d353166322d343132613435306265356363; asc 6dbafa39-7f00-0001-51f2-412a450be5cc;; 1: len 6; hex 000024214f7e; asc $!O~;; 2: len 7; hex 000000400217bc; asc @ ;; 3: len 2; hex 03e9; asc ;; 4: len 2; hex 03e8; asc ;; 5: len 36; hex 65666635323863622d376630302d303030312d336632662d353239626433653361333032; asc eff528cb-7f00-0001-3f2f-529bd3e3a302;; 6: len 40; hex 36646234376337652d376630302d303030312d353166322d3431326132346664656366352e6d7033; asc 6db47c7e-7f00-0001-51f2-412a24fdecf5.mp3;; 7: len 21; hex 416e67656c73204e6f7720436f6e666572656e6365; asc Angels Now Conference;; 8: len 34; hex 416e67656c73204e6f7720436f6e666572656e6365204a756c7920392c2032303131; asc Angels Now Conference July 9, 2011;; 9: len 1; hex 80; asc ;; 10: len 8; hex 8000124a5262bdf4; asc JRb ;; 11: len 8; hex 8000124a57669dc3; asc JWf ;; 12: SQL NULL; 13: len 5; hex 8000012200; asc " ;; 14: len 1; hex 80; asc ;; 15: len 2; hex 83e8; asc ;; 16: len 4; hex 8000000a; asc ;;
But in child table `backoffice`.`attachment`, in index `PRIMARY`, there is a record:
PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 30; hex 36646261666133392d376630302d303030312d353166322d343132613435; asc 6dbafa39-7f00-0001-51f2-412a45;...(truncated); 1: len 30; hex 38666164663561652d376630302d303030312d326436612d636164326361; asc 8fadf5ae-7f00-0001-2d6a-cad2ca;...(truncated); 2: len 6; hex 00002297b3ff; asc " ;; 3: len 7; hex 80000040070110; asc @ ;; 4: len 2; hex 0000; asc ;; 5: len 30; hex 416e67656c73204e6f7720436f6e666572656e636520446f63756d656e74; asc Angels Now Conference Document;;
------------
TRANSACTIONS
------------
Trx id counter 0 620783814
Purge done for trx's n:o < 0 620783800 undo n:o < 0 0
History list length 35
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, process no 29956, OS thread id 1192212800
MySQL thread id 5341758, query id 189708501 127.0.0.1 lwdba
show innodb status
---TRANSACTION 0 620783788, not started, process no 29956, OS thread id 1196472640
MySQL thread id 5341773, query id 189708353 10.64.89.143 viget
---TRANSACTION 0 0, not started, process no 29956, OS thread id 1223895360
MySQL thread id 5341667, query id 189706152 10.64.89.145 viget
---TRANSACTION 0 0, not started, process no 29956, OS thread id 1227888960
MySQL thread id 5341556, query id 189699857 172.16.135.63 lwdba
---TRANSACTION 0 620781112, not started, process no 29956, OS thread id 1222297920
MySQL thread id 5341511, query id 189696265 10.64.89.143 viget
---TRANSACTION 0 620783736, not started, process no 29956, OS thread id 1229752640
MySQL thread id 5339005, query id 189707998 10.64.89.144 viget
---TRANSACTION 0 620783785, not started, process no 29956, OS thread id 1198602560
MySQL thread id 5337583, query id 189708349 10.64.89.145 viget
---TRANSACTION 0 620783469, not started, process no 29956, OS thread id 1224161600
MySQL thread id 5333500, query id 189708478 10.64.89.144 viget
---TRANSACTION 0 620781240, not started, process no 29956, OS thread id 1198336320
MySQL thread id 5324256, query id 189708493 10.64.89.145 viget
---TRANSACTION 0 617458223, not started, process no 29956, OS thread id 1195141440
MySQL thread id 736, query id 175038790 Has read all relay log; waiting for the slave I/O thread to update it
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
519878 OS file reads, 18962880 OS file writes, 13349046 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 6.25 writes/s, 4.50 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 1190, seg size 1192,
174800 inserts, 174800 merged recs, 54439 merges
Hash table size 35401603, node heap has 35160 buffer(s)
0.50 hash searches/s, 11.75 non-hash searches/s
---
LOG
---
Log sequence number 28 1235093534
Log flushed up to 28 1235093534
Last checkpoint at 28 1235091275
0 pending log writes, 0 pending chkp writes
12262564 log i/o's done, 3.25 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 18909316674; in additional pool allocated 1048576
Dictionary memory allocated 2019632
Buffer pool size 1048576
Free buffers 175763
Database pages 837653
Modified db pages 6
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 770138, created 108485, written 7795318
0.00 reads/s, 0.00 creates/s, 4.25 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread process no. 29956, id 1185823040, state: sleeping
Number of rows inserted 6453767, updated 4602534, deleted 3638793, read 388349505551
0.25 inserts/s, 1.25 updates/s, 0.00 deletes/s, 2.75 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================
1 row in set, 1 warning (0.00 sec)
InnoDBのロック待機タイムアウト値を増やすには、 innodb_lock_wait_timeout を設定します。デフォルトは50秒です。
mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50 |
+--------------------------+-------+
1 row in set (0.01 sec)
この行で永久に/etc/my.cnf
のより高い値に設定することができます
[mysqld]
innodb_lock_wait_timeout=120
そしてmysqlを再起動してください。現時点でmysqlを再起動できない場合は、次のコマンドを実行してください。
SET GLOBAL innodb_lock_wait_timeout = 120;
あなたはまたあなたのセッションの間それを設定することができます
SET innodb_lock_wait_timeout = 120;
クエリが続きます
誰かがこの問題に関するSOスレッドの1つで言及したように:時々、テーブルをロックしたプロセスがプロセスリストの中でスリープしているように見えます!問題のデータベースで開かれているすべてのスリープ状態のスレッドを削除するまで、私は髪を引き裂いていました(その時点でアクティブだったスレッドはありませんでした)。これでテーブルのロックが解除され、更新クエリが実行されます。
コメンターは、「MySQLスレッドがテーブルをロックしてから、MySQLに関連しない何かが発生するのを待つ間にスリープする」ようなものに似たものを言った。
show engine innodb status
ログを再確認した後(ロックを担当しているクライアントを突き止めた後)、問題のあるスレッドがトランザクションリストの一番下、アクティブなクエリの下に表示されていることに気付きました。凍結されたロックが原因でエラーが発生しました。
------------------
---TRANSACTION 2744943820, ACTIVE 1154 sec(!!)
2 lock struct(s), heap size 376, 2 row lock(s), undo log entries 1
MySQL thread id 276558, OS thread handle 0x7f93762e7710, query id 59264109 [ip] [database] cleaning up
Trx read view will not see trx with id >= 2744943821, sees < 2744943821
(「Trx read view」メッセージが凍結ロックに関連しているかどうかは不明ですが、他のアクティブなトランザクションとは異なり、このメッセージは発行されたクエリには表示されず、トランザクションは「クリーンアップ」と表示されます。行ロック)
物語の教訓は、トランザクションがスレッドであってもアクティブになることができるということです。 -) は寝ている。
レコードについては、デッドロックがありMySQLがそれを検出できない場合にもロック待機タイムアウト例外が発生するため、タイムアウトします。もう1つの理由は、クエリの実行時間が非常に長くなることです。これは、解決や修復が簡単なので、ここでは説明しません。
MySQLは通常、2つのトランザクション内で「正しく」構築されていれば、デッドロックを処理できます。その後、MySQLはロックの少ないトランザクションを1つだけ終了/ロールバックし(影響が少なくなるので重要ではありません)、もう一方のトランザクションを終了させます。
では、AとBの2つのプロセスと3つのトランザクションがあるとします。
Process A Transaction 1: Locks X
Process B Transaction 2: Locks Y
Process A Transaction 3: Needs Y => Waits for Y
Process B Transaction 2: Needs X => Waits for X
Process A Transaction 1: Waits for Transaction 3 to finish
(see the last two paragraph below to specify the terms in more detail)
=> deadlock
MySQLはデッドロックがあることを認識できないため(3トランザクション以内に及ぶ)、これは非常に不幸な設定です。それでMySQLがすることは…何もない!何をすべきかわからないので、待つだけです。最初に獲得したロックがタイムアウトを超えるまで待機し(プロセスAトランザクション1:ロックX)、これによりロックXのブロックが解除され、トランザクション2のロックが解除されます。
何が(どのクエリ)最初のロックを引き起こしているのかを調べるのが技術です(Lock X)。トランザクション3がトランザクション2を待機していることは簡単にわかりますが(show engine innodb status
)、トランザクション2がどのトランザクションを待っているのか(トランザクション1)はわかりません。 MySQLはトランザクション1に関連したロックやクエリを表示しません。唯一のヒントは、(show engine innodb status
プリントアウトの)トランザクションリストの一番下に、トランザクション1が何もしていないように見えるということです。終わる)。
どのSQLクエリが、待機中の特定のトランザクションに対してロック(ロックX)を許可するかを見つける方法については、 Tracking MySQL query history in long running transactions
を参照してください。
あなたは、プロセスとトランザクションがまさに例にあるのか疑問に思っているならば。プロセスはPHPプロセスです。トランザクションは、 innodb-trx-table で定義されているトランザクションです。私の場合は、2つのPHPプロセスがあり、それぞれに手動でトランザクションを開始しました。興味深いのは、プロセス内で1つのトランザクションを開始したにもかかわらず、MySQLが実際には2つの別々のトランザクションを内部的に使用していたことです。
MySQLは自身のトランザクションを内部的に管理しており、(私の場合は)PHPプロセスから来るすべてのSQL要求を処理するために2つのトランザクションを使用することにしました(プロセスA)。トランザクション1がトランザクション3の終了を待っているという文は、MySQLの内部的なものです。 MySQLはトランザクション1とトランザクション3が実際に1つの「トランザクション」要求の一部としてインスタンス化されていることを「知っていました」(プロセスAから)。トランザクション3(「トランザクション」のサブパート)がブロックされたため、「トランザクション」全体がブロックされました。 「トランザクション」はトランザクション1(「トランザクション」のサブパートでもある)を終了できなかったため、同様に未完了としてマークされました。これが、「トランザクション1がトランザクション3が終了するのを待つ」という意味です。
この例外の大きな問題は、テスト環境では通常再現できないことであり、prodで発生したときにinnodbエンジンのステータスを実行することはできません。そこで、私はこの例外のために以下のコードをキャッチブロックに入れました。それは例外が発生したときに私はエンジンの状態を把握するのに役立ちました。それは大いに役立ちました。
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SHOW ENGINE INNODB STATUS");
while(rs.next()){
log.info(rs.getString(1));
log.info(rs.getString(2));
log.info(rs.getString(3));
}
pt-deadlock-logger
ユーティリティ のmanページを見てください。
brew install percona-toolkit
pt-deadlock-logger --ask-pass server_name
上記のengine innodb status
から情報を抽出し、30秒ごとに実行されるdaemon
を作成するためにも使用できます。
上記のRolandoの答えから推測すると、それはあなたのクエリをブロックしているものです:
---TRANSACTION 0 620783788, not started, process no 29956, OS thread id 1196472640
MySQL thread id 5341773, query id 189708353 10.64.89.143 viget
クエリを実行する必要があり、他のクエリが実行されるのを待つことができない場合は、MySQLスレッドIDを使用してそれらを強制終了します。
kill 5341773
(明らかに、シェル内ではなく、mysql内から)
以下からスレッドIDを見つける必要があります。
show engine innodb status\G
データベースをブロックしているものがどれかを確認します。
あなたが使用することができます:
show full processlist
これは、MySQL内のすべての接続と現在の接続状態、および実行中のクエリを一覧表示します。切り捨てられたクエリと接続統計を表示する、より短いバリエーションshow processlist;
もあります。
これが「他のクエリ」がロックタイムアウトの問題を引き起こした原因を突き止めるために私が最終的にしなければならなかったことです。アプリケーションコードでは、保留中のすべてのデータベース呼び出しをこのタスク専用の別のスレッドで追跡します。いずれかのDB呼び出しがN秒より長くかかる場合(私たちにとっては30秒です)、次のように記録します。
// Pending InnoDB transactions
SELECT * FROM information_schema.innodb_trx ORDER BY trx_started;
// Optionally, log what transaction holds what locks
SELECT * FROM information_schema.innodb_locks;
上記により、デッドロックの原因となっている行をロックしている同時クエリを特定することができました。私の場合、それらはINSERT ... SELECT
のようなステートメントであり、プレーンなSELECTとは異なり基礎となる行をロックします。その後、コードを再編成したり、read uncommittedなどの別のトランザクション分離を使用したりできます。
がんばろう!
JDBCを使用している場合は、次の選択肢があります。
includeInnodbStatusInDeadlockExceptions = true
https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html