2017-02-19 8 views
0

高性能MySQL」の例のようにmysql(innodb)にデッドロックを作成する場合。しかし、あるトランザクションで1行のテストを更新すると、別の行が更新され、最後にタイムアウトになります。それはinnodbのように、行レベルのロックではなく、テーブルレベルのロックを使用して、条件を更新するときに使用します。この状況はinnodbの行レベルロックと一致しません。mysql innodb table lock - 別の行で1行の更新を更新する場合

MySQLバージョン:

mysql> status 
-------------- 
mysql Ver 14.14 Distrib 5.6.26, for Linux (x86_64) using EditLine wrapper 

Connection id:   2 
Current database:  test 
Current user:   [email protected] 
SSL:     Not in use 
Current pager:   stdout 
Using outfile:   '' 
Using delimiter:  ; 
Server version:   5.6.26 MySQL Community Server (GPL) 
Protocol version:  10 
Connection:    Localhost via UNIX socket 
Server characterset: latin1 
Db  characterset: latin1 
Client characterset: utf8 
Conn. characterset: utf8 
UNIX socket:   /var/lib/mysql/mysql.sock 
Uptime:     4 hours 52 min 1 sec 

Threads: 3 Questions: 107 Slow queries: 0 Opens: 69 Flush tables: 1 Open tables: 62 Queries per second avg: 0.006 
-------------- 

mysql> show variables like '%isolation%'; 
+---------------+-----------------+ 
| Variable_name | Value   | 
+---------------+-----------------+ 
| tx_isolation | REPEATABLE-READ | 
+---------------+-----------------+ 
1 row in set (0.00 sec) 

は、テストテーブルを作成します。

mysql> show create table t\G; 
*************************** 1. row *************************** 
     Table: t 
Create Table: CREATE TABLE `t` (
    `a1` int(11) DEFAULT NULL, 
    `b` varchar(10) DEFAULT NULL, 
    `c` varchar(10) DEFAULT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 

ERROR: 
No query specified 

mysql> select * from t; 
+------+------+------+ 
| a1 | b | c | 
+------+------+------+ 
| 1 | a | b | 
| 2 | aa | bb | 
+------+------+------+ 
2 rows in set (0.00 sec) 

次に開い二つの独立したセッションを2つのトランザクションの中

セッション1

mysql> start transaction; 
Query OK, 0 rows affected (0.00 sec) 

mysql> update t set b='x' where a1=2; 
Query OK, 1 row affected (0.00 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

を作成しますessions 2、更新がブロックされ、最終的にロック関係原則

mysql> SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, 
    ->  r.trx_query waiting_query, 
    ->  b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, 
    ->  b.trx_query blocking_query 
    -> FROM  information_schema.innodb_lock_waits w 
    -> INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id 
    -> INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id; 
+----------------+----------------+--------------------------------+-----------------+-----------------+----------------+ 
| waiting_trx_id | waiting_thread | waiting_query     | blocking_trx_id | blocking_thread | blocking_query | 
+----------------+----------------+--------------------------------+-----------------+-----------------+----------------+ 
| 5933   |    6 | update t set c='yy' where a1=1 | 5932   |    5 | NULL   | 
+----------------+----------------+--------------------------------+-----------------+-----------------+----------------+ 
1 row in set (0.00 sec) 

を取得するためのInnoDBプラグインを使用して、ブロック中

mysql> start transaction 
    -> ; 
Query OK, 0 rows affected (0.00 sec) 

mysql> update t set c='yy' where a1=1; 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 

をタイムアウト、セッション1の行ロックは、セッション中に更新をブロックしません2.

このような問題が発生した場合は、セッション2がブロックされた理由を説明してください。

+0

本当にこのテーブルには「PRIMARY KEY」はありませんか?これはInnoDBテーブルの "no-no"です。 –

答えて

0

なしでInnoDBでトランザクションを使用することは考慮しないでください。

UPDATE ... WHERE ai = constantを実行すると、少なくともINDEX(a1)を使用することを真剣に検討してください。

それ以外の場合、InnoDBはインデックスを作成せずに各 "行"を把握することができないため、おそらく "行レベルのロック"に惑わされます。

+0

テストテーブル 'alter table t add主キー(a1);'にプライマリキーを追加した後、innodbはセッション1のデッドロックを検出し、インデクス 'create index ind_t on t(a1);'でinnodbもデッドロックを検出します。プライマリキーとインデックスの違いは、インデックスを使用してセッション1でプライマリキーを使用しているときに、セッション2でデッドロックが検出されたことです。 – camash

+0

(私は、殺すための接続の選択肢が予測可能であると確信していません) –

関連する問題