本文介紹了MySQL死鎖錯(cuò)誤的處理方法,對(duì)大家解決問題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧!
問題描述
我的Web應(yīng)用程序最多每秒運(yùn)行以下查詢1-2次,具體取決于用戶流量:
UPDATE `click_rollups`
SET `clicks` = `clicks` + 1, `last_updated` = ?
WHERE `camp_id` = ?
AND `country` = ?
AND `clicks` < ?
AND `time_created` = ?
我們的日志顯示有時(shí)會(huì)出現(xiàn)此錯(cuò)誤:
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
但是,click_rollups
僅在該事務(wù)的寫上下文中使用一次,因此我無(wú)法想象死鎖會(huì)以何種方式發(fā)生。僅使用SELECT
s在應(yīng)用程序的其他位置查詢一次。
因此,這是否意味著這兩個(gè)獨(dú)立事務(wù)(UPDATE和SELECT-ONLY)的死鎖導(dǎo)致了問題,因?yàn)槊總€(gè)獨(dú)立事務(wù)只使用該表一次(并且使用該表的查詢不引用任何其他表)?或者是否存在行級(jí)鎖定問題,這可能意味著其中一個(gè)事務(wù)可能會(huì)與同一事務(wù)的其他事件發(fā)生死鎖?
InnoDB
進(jìn)一步閱讀后,我發(fā)現(xiàn),由于推薦答案確實(shí)使用行級(jí)鎖定,因此在僅插入或更新單行時(shí)可能會(huì)發(fā)生死鎖,因?yàn)椴僮鞑皇窃拥摹N遗芰耍?/p>
SHOW ENGINE INNODB STATUS
以查找有關(guān)上次死鎖的信息。我發(fā)現(xiàn):
------------------------
LATEST DETECTED DEADLOCK
------------------------
140106 17:22:41
*** (1) TRANSACTION:
TRANSACTION 63EB5222A, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 9 lock struct(s), heap size 3112, 6 row lock(s), undo log entries 2
MySQL thread id 4304350, OS thread handle 0x7fd3b74d3700, query id 173460207 192.168.0.2 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '27739' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1389046866'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB5222A lock_mode X waiting
*** (2) TRANSACTION:
TRANSACTION 63EB52225, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
177 lock struct(s), heap size 31160, 17786 row lock(s), undo log entries 2
MySQL thread id 4304349, OS thread handle 0x7fd6961c8700, query id 173460194 192.168.0.1 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '30949' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1388964767'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 512 n bits 384 index `PRIMARY` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (1)
您可以看到,導(dǎo)致死鎖的兩個(gè)查詢實(shí)際上是完全相同的。它顯示W(wǎng)HERE子句中的列也有不同的參數(shù),因此被鎖定的實(shí)際行是不同的,這似乎有點(diǎn)違反我的直覺-對(duì)不同行集的操作如何會(huì)導(dǎo)致死鎖?
答案似乎是死鎖是由查詢引擎鎖定索引結(jié)構(gòu)中的條目引起的。如果您查看上面的輸出,您可以看到一個(gè)事務(wù)鎖定了country
索引中某個(gè)頁(yè)面的特定部分,并且需要鎖定主鍵索引的一部分,而另一個(gè)事務(wù)基本上是相反的情況。
在我們的應(yīng)用程序的這一部分中有一個(gè)不變量,只有一行的點(diǎn)擊次數(shù)會(huì)少于1000次,所以我相信通過解決這個(gè)問題,死鎖問題將被最小化,因?yàn)榭傮w上會(huì)減少鎖定。MySQL文檔建議對(duì)應(yīng)用程序進(jìn)行編碼,以便在由于死鎖而導(dǎo)致回滾的情況下始終重新發(fā)布事務(wù),這將防止導(dǎo)致頁(yè)面錯(cuò)誤的問題。然而,如果任何人有任何關(guān)于如何實(shí)際避免這些死鎖的其他想法,請(qǐng)?jiān)俅卧谠u(píng)論中發(fā)布它們!
編輯-
country
索引不需要由事務(wù)使用,因?yàn)閷?duì)于每個(gè)camp_id
值,只有幾個(gè)(通常只有1個(gè))不同的country
值,每個(gè)值只對(duì)應(yīng)于一行。我已經(jīng)向查詢添加了一個(gè)索引提示,使其停止使用該索引,該問題現(xiàn)在已得到修復(fù),而不會(huì)對(duì)性能造成任何影響(可能會(huì)有一些小的提高)。
這篇關(guān)于MySQL死鎖錯(cuò)誤的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,