我有一個包含數百萬行的表,我不得不使用數除以組。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
*的列中都有一個索引。「因此,必須在同一時間創建兩個客戶記錄才能產生死鎖」*這不是死鎖意味着什麼。兩個在同一時間不是問題。事務不會死鎖,除非每個人都擁有另一個人需要的鎖,這表明您正在一次事務中執行多次插入。你能證實嗎?如果是這樣,你爲什麼這樣做?如果你沒有刪除一些狀態信息,它也會更容易解釋。 –