2017-02-19 1 views
0

Wenn ein Deadlock in Mysql (Innodb) als das Beispiel auf Seite 10 von "High Performance MySQL" erstellen. Wenn ich jedoch eine Zeile des Tests in einer Transaktion aktualisiere, wird eine weitere Zeile aktualisiert und schließlich ein Timeout ausgelöst. Es ist so, als ob innodb die Sperre auf Tabellenebene anstelle der Sperre auf Zeilenebene verwendet, wenn sie mit where-Bedingung aktualisiert wird. Diese Situation stimmt nicht mit den Sperren auf Zeilenebene von innodb überein.mysql innodb Tabellensperre - wenn Update eine Zeile Block Update auf einer anderen Zeile

Die Mysql Version:

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) 

Testtabelle erstellen:

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) 

Dann öffnen zwei unabhängige Sitzungen zwei Transaktionen

Session 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 

In s erstellen essions 2 wird Update blockiert und schließlich

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 

Während Block Timeout werden, verwenden Sie InnoDB-Plugin die Verriegelungs Beziehung

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) 

Im Prinzip ist die Zeilensperre in Session 1 nicht blockiert Updates in der Sitzung zu erhalten 2.

Wenn Sie auf ein solches Problem gestoßen sind, erklären Sie bitte, warum Sitzung 2 blockiert wurde.

+0

Haben Sie wirklich nicht "PRIMARY KEY" auf diesem Tisch? Das ist ein "no-no" für InnoDB-Tabellen. –

Antwort

0

Verwenden Sie keine Transaktionen in InnoDB ohne PRIMARY KEY.

Und ernsthaft in Betracht ziehen, mindestens zu verwenden, wenn Sie UPDATE ... WHERE ai = constant tun.

Sonst wird InnoDB ziemlich schlampig mit "row level locking" - wahrscheinlich weil es Schwierigkeiten hat, jede "Zeile" ohne Indizierung in den Griff zu bekommen.

+0

Nach dem Hinzufügen des Primärschlüssels in der Testtabelle 'alter table t addieren Sie den Primärschlüssel (a1);', erkennt innodb den Deadlock in Sitzung 1. Und mit index 'create index ind_t auf t (a1);', erkennt innodb auch den Deadlock. Der Unterschied zwischen Primärschlüssel und Index besteht darin, dass Deadlock in Sitzung 2 bei Verwendung des Primärschlüssels in Sitzung 1 bei Verwendung von Index erkannt wird. – camash

+0

(Ich bin nicht davon überzeugt, dass die Wahl der zu tötenden Verbindung vorhersehbar ist.) –

Verwandte Themen