【发布时间】:2017-04-06 08:56:35
【问题描述】:
我的应用程序在更新和插入查询之间遇到了死锁,我无法理解为什么以导致死锁的方式给出锁。
环境-
- 应用程序 - Django
- 数据库 - MySQL 5.7
- 引擎 - Innodb
- 隔离级别 - 已提交阅读。
- 表(为安全起见更改名称)-
- M - 主键 - id
- MSC - 有一个指向 M.id 的外键
- MSC 上的索引
- M(FK) 索引
- S(FK) 索引
- C(FK) 索引
- 唯一共同约束索引(M、S、C)
- MSC 上的索引
查询-以下两个查询(查询被截断以仅显示相关列)-
-
更新-
UPDATE `MSC` SET `m_id` = 110, `s_id` = 1234, `c_id` = '9b39cd', WHERE `MSC`.`id` = 54362 -
插入-
INSERT INTO `MSC` (`m_id`, `s_id`, `c_id`) VALUES (110, 1235, '9b39cd')
死锁-
- 首先触发更新查询,然后触发插入查询,但
SHOW ENGINE INNODB STATUS\G;的输出显示插入查询更早启动。 - 从输出来看,它们的执行时间似乎是在以下方式导致死锁 -
- Insert 获得 MSC 上的独占 (X) 锁并等待外键 M 上的共享 (S) 锁。
- 更新获取 M 上的独占 (X) 锁并等待外键 MSC 上的独占 (X) 锁。
- 以下是完整输出-
MSC(m_id、s_id、c_id)值(110、1235、'9b39cd')
* (1) 等待授予此锁定:
RECORD LOCKS 空间 id 1377 页号 10 n 位 152 表“db”的索引 PRIMARY。“M” trx id 7784084 锁定模式 S 锁定记录但不锁定间隙等待
记录锁,堆号 67 物理记录:n_fields 42;紧凑的格式;信息位 0
0:长度 4;十六进制 800000ac;升序;;
1:长度 6;十六进制 00000076c69f; asc v;;
2:长度 7;十六进制 76000001cb24c5; asc v $ ;;
3:长度 8;十六进制 999be72e2e07032e;上升 .. .;;
4:长度 8;十六进制 999c22fa43025221; asc " C R!;;
*** (2) TRANSACTION:
TRANSACTION 7784095, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
6 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 2
MySQL thread id 493645, OS thread handle 140188694415104, query id 55263635 ip-10-198-3-73.ec2.internal 10.198.3.73 root updating
UPDATE `MSC` SET `m_id` = 110, `s_id` = 1234, `c_id` = '9b39cd', WHERE `MSC`.`id` = 54362
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1377 page no 10 n bits 152 index PRIMARY of table "db"."M" trx id 7784095 lock_mode X locks rec but not gap
Record lock, heap no 67 PHYSICAL RECORD: n_fields 42; compact format; info bits 0
0: len 4; hex 800000ac; asc ;;
1: len 6; hex 00000076c69f; asc v ;;
2: len 7; hex 76000001cb24c5; asc v $ ;;
3: len 8; hex 999be72e2e07032e; asc .. .;;
4: len 8; hex 999c22fa43025221; asc " C R!;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1410 page no 261 n bits 104 index PRIMARY of table "db"."MSC" trx id 7784095 lock_mode X locks rec but not gap waiting
Record lock, heap no 16 PHYSICAL RECORD: n_fields 16; compact format; info bits 0
0: len 4; hex 800038e2; asc 8 ;;
1: len 6; hex 00000076c694; asc v ;;
2: len 7; hex 6f0000055b2a0e; asc o [* ;;
3: len 8; hex 999c22fa0d08a51c; asc " ;;
4: len 8; hex 999c22fa3b0dffd8; asc " ; ;;
*** WE ROLL BACK TRANSACTION (2)
问题- 我无法理解以下内容- 1. 为什么更新查询必须等待,而插入查询得到锁却得不到锁? 2. 为什么更新查询需要/占用M表的排他(X)锁。
请在这里分享您的想法。如果需要任何额外信息,请告诉我。
【问题讨论】:
-
Saurabh,我不是 MySQL 专家,但输出表明至少事务 #1 不仅仅执行这个查询:请参阅
46 row lock(s), undo log entries 25,这对于单个INSERT来说很奇怪.所以应该猜猜这个INSERTquery 会导致什么场景并分析整个事务。第二笔交易可能也是如此。当您看到两个事务中的所有查询时,将更容易理解实际发生的情况。附言问题中的输出是 full output 还是还有其他什么?仅凭这种冲突似乎不足以陷入僵局。 -
我在锁和隔离级别方面也不是那么专家。但是在你的情况下,dealock 很好理解。一个 sql 在列上获得了排他锁,其他 sql 正在等待,反之亦然。我怀疑 FK -PK约束。想看看是循环还是循环?这些表关系在其他表中,是否定义了级联。
-
我也在考虑同一行,即在 2 diff trans 中编写 2 语句。但我仍然会调查其他事情。因为你的问题还没有结束。
-
请提供
MSC的所有索引。请提供其余部分或BEGIN与遇到问题的查询之间的查询。 -
您是否有任何存储过程可能导致基于插入和/或更新的问题?另外,您确定根据您的密钥,您的更新不会导致基于密钥唯一性的冲突吗?
标签: mysql django database deadlock