我该如何调试这个mysql死锁?

时间:2017-10-28 09:02:50

标签: mysql database-deadlocks

我在MySQL InnoDB表中遇到了死锁。 InnoDB日志精确定位导致死锁的两个查询(它是两个完全相同的查询,两个完全相同的事务的部分,由几乎同时的API重复请求产生)。但我无法理解是什么问题 - 查询只是连续更新了一些字段,为什么它会死锁?

以下是查询示例:

update `some_table` set `some_field` = 123 where `some_table`.`id` = 530;

下面我粘贴了InnoDB show engine innodb status;的死锁日志。令我感到困惑的是(2) TRANSACTIONHOLDS THE LOCK行中的WAITING FOR THIS LOCK TO BE GRANTEDLATEST DETECTED DEADLOCK ------------------------ 2017-10-28 11:50:42 0x7f9d586d2700 *** (1) TRANSACTION: TRANSACTION 14425003, ACTIVE 1 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 5 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 4662, OS thread handle 140313765725952, query id 6441114 localhost 127.0.0.1 app updating update `some_table` set `some_field` = 123 where `some_table`.`id` = 530 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 148 page no 15 n bits 96 index PRIMARY of table `some_schema`.`some_table` trx id 14425003 lock_mode X locks rec but not gap waiting Record lock, heap no 14 PHYSICAL RECORD: n_fields 30; compact format; info bits 0 0: len 8; hex 8000000000000212; asc ;; 1: len 6; hex 000000dc1b3a; asc :;; 2: len 7; hex 350000013227b6; asc 5 2' ;; 3: len 8; hex 8000000000000006; asc ;; 4: SQL NULL; 5: len 4; hex 80000000; asc ;; 6: len 28; hex d09ed0bad181d0bad0b8d0b520d181d0b0d0b4d18b20283530333029; asc (5030);; 7: len 30; hex d09fd0bed181d0b5d0bbd0bed0ba2022d09ed0bad181d0bad0b8d0b520d1; asc " ; (total 38 bytes); 8: len 12; hex d0add092d0a0d098d09ad090; asc ;; 9: len 4; hex 312e3732; asc 1.72;; 10: len 8; hex 8000000000000023; asc #;; 11: SQL NULL; 12: len 30; hex 30820122300d06092a864886f70d01010105000382010f003082010a0282; asc 0 "0 * H 0 ; (total 294 bytes); 13: SQL NULL; 14: len 1; hex 9d; asc ;; 15: len 30; hex 353030303a333b3530303a333b313030303a33313b35303a353b3130303a; asc 5000:3;500:3;1000:31;50:5;100:; (total 32 bytes); 16: len 4; hex 800001f4; asc ;; 17: len 8; hex 8000015f622b7acf; asc _b+z ;; 18: SQL NULL; 19: SQL NULL; 20: len 1; hex 80; asc ;; 21: len 1; hex 81; asc ;; 22: len 1; hex 81; asc ;; 23: len 1; hex 81; asc ;; 24: len 4; hex 77696669; asc wifi;; 25: len 7; hex 6d656761666f6e; asc megafon;; 26: len 8; hex 8000015f5d43771a; asc _]Cw ;; 27: len 30; hex 4a1a42c600000230000007d700000772000007b3000007e1000007e20000; asc J B 0 r ; (total 48 bytes); 28: len 8; hex 5cbdd55bbd55e93f; asc \ [ U ?;; 29: len 4; hex 80000000; asc ;; *** (2) TRANSACTION: TRANSACTION 14425004, ACTIVE 1 sec starting index read mysql tables in use 1, locked 1 5 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 4663, OS thread handle 140313770141440, query id 6441120 localhost 127.0.0.1 app updating update `some_table` set `some_field` = 123 where `some_table`.`id` = 530 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 148 page no 15 n bits 96 index PRIMARY of table `some_schema`.`some_table` trx id 14425004 lock mode S locks rec but not gap Record lock, heap no 14 PHYSICAL RECORD: n_fields 30; compact format; info bits 0 0: len 8; hex 8000000000000212; asc ;; 1: len 6; hex 000000dc1b3a; asc :;; 2: len 7; hex 350000013227b6; asc 5 2' ;; 3: len 8; hex 8000000000000006; asc ;; 4: SQL NULL; 5: len 4; hex 80000000; asc ;; 6: len 28; hex d09ed0bad181d0bad0b8d0b520d181d0b0d0b4d18b20283530333029; asc (5030);; 7: len 30; hex d09fd0bed181d0b5d0bbd0bed0ba2022d09ed0bad181d0bad0b8d0b520d1; asc " ; (total 38 bytes); 8: len 12; hex d0add092d0a0d098d09ad090; asc ;; 9: len 4; hex 312e3732; asc 1.72;; 10: len 8; hex 8000000000000023; asc #;; 11: SQL NULL; 12: len 30; hex 30820122300d06092a864886f70d01010105000382010f003082010a0282; asc 0 "0 * H 0 ; (total 294 bytes); 13: SQL NULL; 14: len 1; hex 9d; asc ;; 15: len 30; hex 353030303a333b3530303a333b313030303a33313b35303a353b3130303a; asc 5000:3;500:3;1000:31;50:5;100:; (total 32 bytes); 16: len 4; hex 800001f4; asc ;; 17: len 8; hex 8000015f622b7acf; asc _b+z ;; 18: SQL NULL; 19: SQL NULL; 20: len 1; hex 80; asc ;; 21: len 1; hex 81; asc ;; 22: len 1; hex 81; asc ;; 23: len 1; hex 81; asc ;; 24: len 4; hex 77696669; asc wifi;; 25: len 7; hex 6d656761666f6e; asc megafon;; 26: len 8; hex 8000015f5d43771a; asc _]Cw ;; 27: len 30; hex 4a1a42c600000230000007d700000772000007b3000007e1000007e20000; asc J B 0 r ; (total 48 bytes); 28: len 8; hex 5cbdd55bbd55e93f; asc \ [ U ?;; 29: len 4; hex 80000000; asc ;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 148 page no 15 n bits 96 index PRIMARY of table `some_schema`.`some_table` trx id 14425004 lock_mode X locks rec but not gap waiting Record lock, heap no 14 PHYSICAL RECORD: n_fields 30; compact format; info bits 0 0: len 8; hex 8000000000000212; asc ;; 1: len 6; hex 000000dc1b3a; asc :;; 2: len 7; hex 350000013227b6; asc 5 2' ;; 3: len 8; hex 8000000000000006; asc ;; 4: SQL NULL; 5: len 4; hex 80000000; asc ;; 6: len 28; hex d09ed0bad181d0bad0b8d0b520d181d0b0d0b4d18b20283530333029; asc (5030);; 7: len 30; hex d09fd0bed181d0b5d0bbd0bed0ba2022d09ed0bad181d0bad0b8d0b520d1; asc " ; (total 38 bytes); 8: len 12; hex d0add092d0a0d098d09ad090; asc ;; 9: len 4; hex 312e3732; asc 1.72;; 10: len 8; hex 8000000000000023; asc #;; 11: SQL NULL; 12: len 30; hex 30820122300d06092a864886f70d01010105000382010f003082010a0282; asc 0 "0 * H 0 ; (total 294 bytes); 13: SQL NULL; 14: len 1; hex 9d; asc ;; 15: len 30; hex 353030303a333b3530303a333b313030303a33313b35303a353b3130303a; asc 5000:3;500:3;1000:31;50:5;100:; (total 32 bytes); 16: len 4; hex 800001f4; asc ;; 17: len 8; hex 8000015f622b7acf; asc _b+z ;; 18: SQL NULL; 19: SQL NULL; 20: len 1; hex 80; asc ;; 21: len 1; hex 81; asc ;; 22: len 1; hex 81; asc ;; 23: len 1; hex 81; asc ;; 24: len 4; hex 77696669; asc wifi;; 25: len 7; hex 6d656761666f6e; asc megafon;; 26: len 8; hex 8000015f5d43771a; asc _]Cw ;; 27: len 30; hex 4a1a42c600000230000007d700000772000007b3000007e1000007e20000; asc J B 0 r ; (total 48 bytes); 28: len 8; hex 5cbdd55bbd55e93f; asc \ [ U ?;; 29: len 4; hex 80000000; asc ;; *** WE ROLL BACK TRANSACTION (2) 是相同的 - 好像它们都持有锁并等待它。

我对InnoDB中的死锁处理不熟悉,所以可能我错过了一些东西。这有什么不对?

{{1}}

1 个答案:

答案 0 :(得分:0)

我猜这个死锁是由您的主键上的共享锁引起的。 Here是官方文档的链接,说明死锁的发生方式。

然后,我调查您的问题,并进行一些调查以尝试重现此僵局。 首先,让我们分析您的死锁日志:

  1. 2个与此死锁相关的交易。
  2. Transaction (1) id = 14425003
  3. Transaction (2) id = 14425004
  4. Transaction (2)在检测到死锁后最终回滚。
  5. Transaction (2)保持锁定模式S锁定录音但不锁定间隙
  6. Transaction (2)等待lock_mode X locks rec but not gap
  7. Transaction (1)等待lock_mode X locks rec but not gap

总而言之,Transaction (2)按住RECORD LOCK S并想获得RECORD LOCK X,同时Transaction (1)想要得到RECORD LOCK X。他们彼此阻塞,然后发生死锁。

使用select * where id = 530 lock in share mode授予RECORD LOCK S很简单,但是,我认为您可能不会在应用程序中使用此查询。

这时,我们需要知道何时将RECORD LOCK S添加到主索引。以下来自msyql offical document

如果发生重复键错误,则重复索引上的共享锁 记录已设置。共享锁的这种使用可能会导致死锁, 如果有另一个会话,则有多个会话尝试插入同一行 会话已具有排他锁。如果另一个 会话删除该行。假设InnoDB表t1具有 以下结构:

这样,必须有一些查询要插入或更新,并且出现重复键错误。


以下是如何重现这种死锁的方法:

1。创建表:

CREATE TABLE `t` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  PRIMARY KEY (`id`),
  unique key `p_name` (`name`)
) ENGINE=InnoDB CHARSET=utf8;

2。准备数据:

insert into t (name) value ('A'), ('C'), ('D');

3。重现步骤

+-------------------------------------------+--------------------------------------+
|                 Session A                 |              Session B               |
+-------------------------------------------+--------------------------------------+
| begin;                                    |                                      |
|                                           | begin;                               |
| insert into t (id, name) values (4, 'E'); |                                      |
| update t set name = 'C' where id = 4;     |                                      |
|                                           | update t set name = 'C' where id = 2;|
|                                           | BLOCKED                              |
| update t set name = 'C' where id = 2;     |                                      |
| DEADLOCK OCCUR                            |                                      |
+-------------------------------------------+--------------------------------------+

4。最终的死锁日志如下

------------------------
LATEST DETECTED DEADLOCK
------------------------
2020-07-23 07:19:39 0x7f8cc819e700
*** (1) TRANSACTION:
TRANSACTION 2774, ACTIVE 4 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 12, OS thread handle 140242628749056, query id 9719 192.168.48.1 root updating
/* ApplicationName=PyCharm 2019.1.1 */ update t set name = 'C' where id = 2
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 64 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 2774 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 8; hex 8000000000000002; asc         ;;
 1: len 6; hex 000000000ad0; asc       ;;
 2: len 7; hex a90000011d0120; asc        ;;
 3: len 1; hex 43; asc C;;

*** (2) TRANSACTION:
TRANSACTION 2773, ACTIVE 424 sec starting index read
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 1
MySQL thread id 8, OS thread handle 140242629289728, query id 9729 192.168.48.1 root updating
/* ApplicationName=PyCharm 2019.1.1 */ update t set name = 'C' where id = 2
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 64 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 2773 lock mode S locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 8; hex 8000000000000002; asc         ;;
 1: len 6; hex 000000000ad0; asc       ;;
 2: len 7; hex a90000011d0120; asc        ;;
 3: len 1; hex 43; asc C;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 64 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 2773 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 8; hex 8000000000000002; asc         ;;
 1: len 6; hex 000000000ad0; asc       ;;
 2: len 7; hex a90000011d0120; asc        ;;
 3: len 1; hex 43; asc C;;

*** WE ROLL BACK TRANSACTION (1)

5。如何预防

  • 避免或减少重复值的插入或更新
  • 不要使用唯一索引,而要让应用程序确保值唯一
  • 减少并发查询。
相关问题