我有一个包含数百万行的表,我不得不使用数除以组。MySQL - 触发器调用两次会导致死锁
CREATE TABLE `customers` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`group_id` INT(10) UNSIGNED NULL DEFAULT NULL
)
所以叫我做很多时候是
SELECT COUNT(*) FROM customers WHERE group_id=XXX
但不幸的是MySQL是很慢(> 10秒为一个呼叫)在几十上百万行的表计数时。
所以我决定创建一个新表,只保留计数器:
CREATE TABLE `customer_stats` (
`group_id` INT(11) NOT NULL,
`value` INT(11) NOT NULL,
)
在那里我可以保持当前计数器,并确保它是由使用触发器日期。
所以我有一个触发器插入/更新/删除,这里的例子插入之一:
CREATE TRIGGER `customers_insert` AFTER INSERT ON `customers` FOR EACH ROW
BEGIN
UPDATE customer_stats
SET
`value` = `value` + 1
WHERE
customer_stats.group_id = NEW.group_id;
END
,并在大多数情况下工作得很好,但在高负荷(几十每秒电话)我有死锁。
2016-09-21T20:14:30.639907Z 2057 [Note] InnoDB: Transactions deadlock detected, dumping detailed information.
2016-09-21T20:14:30.639926Z 2057 [Note] InnoDB:
*** (1) TRANSACTION:
TRANSACTION 10390, ACTIVE 0 sec starting index read
mysql tables in use 2, locked 2
LOCK WAIT 10 lock struct(s), heap size 1136, 5 row lock(s), undo log entries 1
MySQL thread id 2059, OS thread handle 140376644818688, query id 85330 test_test-php-fpm_1.test_default 172.19.0.12 root updating
UPDATE customer_stats
SET
`value` = `value` + 1
WHERE
customer_stats.group_id = NEW.group_id;
2016-09-21T20:14:30.639968Z 2057 [Note] InnoDB: *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 85 page no 3 n bits 72 index customer_stats_key_group_id_unique of table `test`.`customer_stats` trx id 10390 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 21; hex 637573746f6d657264657461696c735f636f756e74; asc customerdetails_count;;
1: len 4; hex 80000002; asc ;;
2: len 6; hex 000000002890; asc (;;
3: len 7; hex 34000002341224; asc 4 4 $;;
4: len 4; hex 80000666; asc f;;
2016-09-21T20:14:30.640302Z 2057 [Note] InnoDB: *** (2) TRANSACTION:
TRANSACTION 10391, ACTIVE 0 sec starting index read
mysql tables in use 2, locked 2
10 lock struct(s), heap size 1136, 5 row lock(s), undo log entries 1
MySQL thread id 2057, OS thread handle 140376513820416, query id 85333 test_test-php-fpm_1.test_default 172.19.0.12 root updating
UPDATE customer_stats
SET
`value` = `value` + 1
WHERE
customer_stats.group_id = NEW.group_id;
2016-09-21T20:14:30.640334Z 2057 [Note] InnoDB: *** (2) HOLDS THE LOCK(S):
2016-09-21T20:14:30.640850Z 2057 [Note] InnoDB: *** WE ROLL BACK TRANSACTION (2)
它只存在于高负荷,我不知道是否有改变触发,以确保一些简单的方法,他们不尝试在同一时间执行该UPDATE customer_stats
,因为这是造成僵局。因此,必须在同一时间创建两个客户记录以提高死锁率。
触发器的表格和系统我有点复杂一点,但我尽量简化它,我可以解释你是什么问题。
你试过'group_id'上的索引吗? – Solarflare
@Solarflare是的,在这两个表 – atay
*的列中都有一个索引。“因此,必须在同一时间创建两个客户记录才能产生死锁”*这不是死锁意味着什么。两个在同一时间不是问题。事务不会死锁,除非每个人都拥有另一个人需要的锁,这表明您正在一次事务中执行多次插入。你能证实吗?如果是这样,你为什么这样做?如果你没有删除一些状态信息,它也会更容易解释。 –