2017-07-20 24 views
0

トランザクションの単純なINSERTステートメントがMySQLのさまざまな行でDELETEステートメントをブロックし、最終的にロックタイムアウトエラーでDELETEステートメントセッションタイムアウトが発生するというシナリオがアプリケーションにあります。mysqlロック待ちタイムアウトエラー

以下の簡単なシナリオで状況を説明しようとしました。ただし、DELETEのWHERE句に2つのカラムがある場合は、ロック待機タイムアウトが表示されます。また、トランザクションを開始した後、他の処理をほとんど行う必要がないため、コミットまたはロールバックするのに数分かかることに注意してください。私が挿入しようとしているものとは異なるレコードを削除しても、MySQLはそれをブロックするとは信じがたいです。

セッション1: -

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation; 

+-----------------------+----------------+------------------------+ 
| @@GLOBAL.tx_isolation | @@tx_isolation | @@session.tx_isolation | 
+-----------------------+----------------+------------------------+ 
| READ-COMMITTED  | READ-COMMITTED | READ-COMMITTED   | 
+-----------------------+----------------+------------------------+ 

1 row in set (0.02 sec)` 

mysql> create table testtab(col1 int, col2 int); 
Query OK, 0 rows affected (0.53 sec) 
mysql> START TRANSACTION; 
Query OK, 0 rows affected (0.00 sec) 
mysql> INSERT INTO testtab values(1,1); 
Query OK, 1 row affected (0.00 sec) 
mysql> INSERT INTO testtab values(2,2); 
Query OK, 1 row affected (0.00 sec) 

セッション2: -

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation; 
+-----------------------+----------------+------------------------+ 
| @@GLOBAL.tx_isolation | @@tx_isolation | @@session.tx_isolation | 
+-----------------------+----------------+------------------------+ 
| READ-COMMITTED  | READ-COMMITTED | READ-COMMITTED   | 
+-----------------------+----------------+------------------------+ 
1 row in set (0.00 sec) 
mysql> DELETE FROM testtab where col1=3; 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 

任意の提案ですか?

答えて

0

これは、InnoDBロックがどのように機能するかによるものです。 manual

ロック読み取り、UPDATEを引用、またはSQL文の処理でスキャンされているすべてのインデックスレコード上の一般設定レコードロックを削除します。行を除外する文のWHERE条件があるかどうかは関係ありません。 InnoDBは正確なWHERE条件を覚えていませんが、スキャンされたインデックス範囲のみを知っています。

それは

あなたが文を処理するために、テーブル全体をスキャンする必要がありますあなたの声明とMySQLに適した一切のインデックスを持っていない場合は、テーブルのすべての行は、ロックされていることも注目に値しますひいてはブロックですべてのユーザーが他のユーザーによってテーブルに挿入されます。クエリが不必要に多くの行をスキャンしないように、適切なインデックスを作成することが重要です。

したがって、あなたのケースでは、2つのinsertが2つのロックされた行をテーブルに追加するということが起こります。適切なインデックスがないため、deleteはテーブル全体をスキャンします。見つけたすべての行をロックする必要がありますが、実行するには、insertによって作成されたロックが解除されるのを待たなければなりません(これは時間が経つわけではありません)。

col1にインデックスを追加するdeleteのみ考える(およびロック)しなければならないように、それはインデックスを使用して見つけることができるcol1 = 3と行をこの問題を解決し、従ってそれが他によって挿入された行とは重なりを持たないであろうトランザクション。

"two-column-where-condition"に適したインデックスを見つける際に問題がある場合は、その詳細を追加する必要があります。その状況に適したインデックスが存在する可能性があります。

これはもちろん、実際には同じ行を変更したい場合など、すべての状況を防止するものではないため、トランザクションをできるだけ短くしておくことをお勧めします。必要に応じてトランザクションを繰り返す準備をすることができます。

これは、InnoDBロックの完全な説明ではなく、状況を説明する部分だけです。

+0

Solarflareに感謝します。あなたは一所懸命でした。クエリをブロックする(セッション2のみの完全なprocesslist showクエリを表示する)場合、私はどのようなオプションを持っているのですか?類似の例については – DBPlayer

+0

です。私はshow engine innodb status、full process list etcを試してみましたが、実際にトランザクションを長時間実行させているINSERT文は何も表示されていないようです。 – DBPlayer

関連する問題