【问题标题】:How do I debug this mysql deadlock?如何调试这个mysql死锁?
【发布时间】:2020-07-23 15:24:49
【问题描述】:

我的 MySQL InnoDB 表出现死锁。 InnoDB 日志指出了导致死锁的两个查询(这是两个完全相同的查询,都是完全相同的事务的两个部分,由几乎同时重复的 API 请求产生)。但我不明白是什么问题——查询只是连续更新了一些字段,为什么会死锁?

以下是查询示例:

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

下面我粘贴了来自 InnoDB show engine innodb status; 的死锁日志。令我困惑的是,对于 (2) TRANSACTION 中的行 HOLDS THE LOCKWAITING FOR THIS LOCK TO BE GRANTED 是一样的——就好像它既持有锁又在等待它。

我是 InnoDB 中死锁处理的新手,所以我可能遗漏了一些东西。这里有什么问题?

LATEST 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)

【问题讨论】:

  • 我遇到了同样的问题,但有 2 个相同的插入查询。

标签: mysql database-deadlocks


【解决方案1】:

我猜这个死锁是由你的主键上的共享锁引起的。 Here是官方文档的链接,死锁是怎么发生的。

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

  1. 2 个与此死锁相关的事务。
  2. Transaction (1) id = 14425003
  3. Transaction (2) id = 14425004
  4. Transaction (2) 在检测到死锁后最终回滚。
  5. Transaction (2)hold 锁定模式 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

如果发生重复键错误,重复索引上的共享锁 记录被设定。这种共享锁的使用可能会导致死锁 如果另一个会话尝试插入同一行,则有多个会话 session 已经有一个独占锁。如果另一个 session 删除该行。假设 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.如何预防

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    相关资源
    最近更新 更多