Почему два одновременных оператора удаления + вставки тупиковые на пустой таблице? - PullRequest
0 голосов
/ 07 июня 2018

Мне любопытно узнать, почему два одновременных оператора DELETE, за которыми следуют INSERT операторы, использующие первичные ключи, вызывают тупик в MySQL, когда первичные ключи не существуют.Пример предназначен для иллюстрации проблемы в ее простейшей форме.

Вот настройка.

> SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
+-------------------------+------------------+
| @@GLOBAL.tx_isolation   | @@tx_isolation   |
|-------------------------+------------------|
| REPEATABLE-READ         | REPEATABLE-READ  |
+-------------------------+------------------+
1 row in set
Time: 0.002s

> select version();
+-------------+
| version()   |
|-------------|
| 5.7.12      |
+-------------+
1 row in set
Time: 0.002s

create table lock_test ( id int(11) not null, primary key (`id`) );

Ниже 1> представляет один mysql терминал, а 2> представляет другой.

1> begin;
1> delete from lock_test where id = 1;

2> begin;
2> delete from lock_test where id = 2;

1> insert into lock_test values (1); -- hangs

2> insert into lock_test values (2);
*** deadlock ***

Вот вывод show engine innodb status:

------------------------
LATEST DETECTED DEADLOCK
------------------------
2018-06-06 16:15:18 0x70000ba52000
*** (1) TRANSACTION:
TRANSACTION 807765, ACTIVE 46 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 620, OS thread handle 123145496289280, query id 43097 localhost ::1 root update
insert into lock_test values (1)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 6819 page no 3 n bits 72 index PRIMARY of table `content_graph`.`lock_test` trx id 807765 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) TRANSACTION:
TRANSACTION 807766, ACTIVE 37 sec inserting
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 617, OS thread handle 123145497681920, query id 43099 localhost ::1 root update
insert into lock_test values (2)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 6819 page no 3 n bits 72 index PRIMARY of table `content_graph`.`lock_test` trx id 807766 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 6819 page no 3 n bits 72 index PRIMARY of table `content_graph`.`lock_test` trx id 807766 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

*** WE ROLL BACK TRANSACTION (2)

Обратите внимание, что если вы сначала вставите записи с идентификаторами 1 и 2, а затем повторите описанную выше последовательность, то тупика не будет.

Я чувствую, что, поскольку ключ отсутствует в индексе (оба добавляются), удаление должно блокировать большую часть индекса (большую часть страницы, в которую попадет основной файл), но я хочу убедиться, что у меня естьмое понимание верно.

1 Ответ

0 голосов
/ 07 июня 2018

"Пробел" заблокирован в ожидании того, что кто-то может попытаться вставить строку, которую я пытаюсь удалить.

Или, если посмотреть на это по-другому ... Это было бы слишком медленно, чтобы отлично справитьсякаждый странный случай.Таким образом, InnoDB выбирает эффективную обработку большинства случаев и ставит в тупик редкий случайный случай.

Итог: живи с этим.Вы получите тупики.Вы не обязательно сможете понять их.Но ваш код нужно восстановить - просто откатившись и вернувшись к BEGIN.

...