我一直有一个特定的更新查询,这似乎应该是非常没有问题的各种麻烦。我已经改变了名称,但该表是:Innodb更新锁定
CREATE TABLE `problem_table` (
`id` int(11) NOT NULL,
`type` enum('TYPE1','TYPE2','TYPE3') NOT NULL,
`date` datetime NOT NULL,
`reference_id` int(11) DEFAULT NULL,
`value` varchar(255) NOT NULL,
`source` varchar(16) DEFAULT NULL,
`problem_field` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `type_idx` (`type`),
KEY `value_idx` (`value`(12)),
KEY `latest_id` (`reference_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
和查询造成的问题是:
UPDATE problem_table SET problem_field = 20000101 WHERE id = 6526153;
值的problem_field
和id
这里就不似乎是很重要的。
这个单一的更新是在problem_table
上的各种选择查询反复死锁,所以我的问题是 - 这个简单的更新查询取出了什么锁?我应该补充说,这两个死锁事务只包含单个查询。
我已阅读the docs但他们似乎并不特别全面。
供参考,在这里是它和它的INNODB状态报告死锁的查询,虽然这仅仅是一个例子了许多不同的查询:
INSERT INTO temp
SELECT
p.*,
DATE(p.date)
FROM
problem_table p
WHERE p.type IN ('TYPE1', 'TYPE2')
AND p.source = 'FOO';
------------------------
LATEST DETECTED DEADLOCK
------------------------
161107 0:00:00
*** (1) TRANSACTION:
TRANSACTION 3C7788A94, ACTIVE 69 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 10 lock struct(s), heap size 1248, 7 row lock(s), undo log entries 6
MySQL thread id 6558222, OS thread handle 0x7f44a606d700, query id 3110073624 164.55.80.105 sym_dbuser Updating
-- user=XXX progname=XXX host=XXX pid=XXX ldsn=XXX
-- DBI::db=HASH(0x1d15ecb0)
UPDATE problem_table SET problem_field = 'XXXX-XX-XX XX:XX:XX'WHERE id = 'XXXXX'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1069083 page no 313 n bits 280 index `PRIMARY` of table `XXX`.`problem_table` trx id 3C7788A94 lock_mode X locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION 3C766F450, ACTIVE 831 sec fetching rows, thread declared inside InnoDB 39
mysql tables in use 2, locked 2
47612 lock struct(s), heap size 5339576, 9395927 row lock(s), undo log entries 9194153
MySQL thread id 6558799, OS thread handle 0x7f4203cb6700, query id 3108758081 172.29.1.16 XXX Sending data
-- user=XXX progname=XXX host=XXX pid=XXX [email protected]
INSERT INTO temp
SELECT
p.*,
DATE(p.date)
FROM
problem_table p
WHERE p.type IN ('TYPE1', 'TYPE2')
AND p.source = 'FOO';
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1069083 page no 313 n bits 280 index `PRIMARY` of table `XXX`.`problem_table` trx id 3C766F450 lock mode S
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1069083 page no 82008 n bits 280 index `PRIMARY` of table `XXX`.`problem_table` trx id 3C766F450 lock mode S waiting
*** WE ROLL BACK TRANSACTION (2)
编辑:
对于任何人的利益读下来,我发现INNODB能够检测3个或更多事务的死锁,但它只列出受害者和希望受害者锁定在死锁报告中的事务 - 其余事务不是在那里列出。
看到这一点,运行三个交易,如:
T(ransaction)1 take S lock on R(ecord) 1
T2 take S lock on R2
T2 take X lock on R1 (hangs waiting for T1)
T3 take S lock on R3
T3 take X lock on R2 (hangs waiting for T2)
T1 take X lock on R3 (deadlock detected)
nope,它是无触发的 – rbennett485
它看起来像INSERT INTO临时SELECT ... - 查询锁定problem_table。所以如果这个INSERT INTO查询发生,你的更新查询就会等待。根据行数量(超过9百万个被锁定),这可能会导致更新查询失败,因为在有用的时间内无法获得日志。你有一个缓慢的查询日志,你能看到,这些插入查询需要多长时间以及它们执行的频率? – Seb
@Seb我确实有一个缓慢的查询日志,但这些更新没有出现在它中 - 它们只是出现死锁,在这种情况下,其他事务总是受害者 – rbennett485