2011-04-11 63 views
1

我需要一個專家建議。我的MySQL死鎖場景 - 需要建議

背景 PHP /笨 的mysqli InnoDB表 - fares_table 存儲過程

後端 - 一個cronjob PHP腳本被寫入插入(從服務)/更新數據爲每隔幾分鐘fares_table。 (正常的sql查詢)

前端 - 用戶將能夠讀取這些數據 (該查詢寫入存儲過程的形式,因爲它涉及到許多表的連接,因此我的存儲過程已創建臨時表從fares_table並加入到其它表)

問題

Deadlock found when trying to get lock; try restarting transaction

如果用戶發生在前端絆倒而fares_table正在更新/插入可能會發生死鎖。更新語句發生死鎖

死鎖是由存儲過程試圖等待鎖釋放,同時嘗試使用fares_table 中的select語句創建臨時表而造成的,而後端正在執行插入或更新嘗試等待鎖定發佈。

LATEST DETECTED DEADLOCK 
------------------------ 
110408 9:05:45 
*** (1) TRANSACTION: 
TRANSACTION 0 203543446, ACTIVE 0 sec, OS thread id 6584 fetching rows 
mysql tables in use 2, locked 2 
LOCK WAIT 761 lock struct(s), heap size 60736, 30170 row lock(s) 
MySQL thread id 86268, query id 135039790 XXXXXXX Copying to t 
CREATE TEMPORARY TABLE tmp_tb1 AS SELECT MIN(fare) as cheapest_fare,flighttype origin,destination .... 
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 0 page no 18433 n bits 240 index `PRIMARY` of table `db_name`.`fares_table` 
Record lock, heap no 85 PHYSICAL RECORD: n_fields 18; compact format; info bits 0 
0: len 4; hex 8025d996; asc % ;; 1: len 6; hex 00000c21d3a9; asc ! ;; 2: len 7; hex 0000000b031 

*** (2) TRANSACTION: 
TRANSACTION 0 203543465, ACTIVE 0 sec, OS thread id 3080 updating or deleting, thread declared inside 
mysql tables in use 1, locked 1 
3 lock struct(s), heap size 320, 2 row lock(s), undo log entries 1 
MySQL thread id 85631, query id 135039816 XXXXX Updating 
UPDATE `fares_table` SET `fare` = 2552.85, `currency` = 'AUD'.. 
*** (2) HOLDS THE LOCK(S): 
RECORD LOCKS space id 0 page no 18433 n bits 240 index `PRIMARY` of table `db_name`.`fares_table` 
Record lock, heap no 85 PHYSICAL RECORD: n_fields 18; compact format; info bits 0 
0: len 4; hex 8025d996; asc % ;; 1: len 6; hex 00000c21d3a9; asc ! ;; 2: len 7; hex 0000000b031 

*** (2) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 0 page no 2086 n bits 600 index `flighttype_idx` of table `db_name`.`fares_table` 
Record lock, heap no 218 PHYSICAL RECORD: n_fields 4; compact format; info bits 0 
0: len 7; hex 4f6e6520776179; asc One way;; 1: len 3; hex 424e45; asc BNE;; 2: len 8; hex 8000124a588 

*** WE ROLL BACK TRANSACTION (2) 

我臨時的解決辦法

捕捉數據庫錯誤1213並重試更新查詢。它現在可以工作,但我想找到一個更好的防止死鎖的解決方案。 任何專業建議?

我要如何改變,以防止死鎖或將複製的flighttype_idx有助於指數?

回答

0

由於創建臨時表的查詢由於聚合函數MIN(fare)需要基本鎖定表的主要部分,並且票價更新需要等待完成,所以不存在可以解決死鎖的簡單重新排序。

倒不如通過明確的鎖定機制包圍爭,或許在鎖表只是爲了這個目的,而不是讓交易競爭,然後必須回滾。特別是,create table語句cannot be rolled back,看起來很奇怪。請參閱LOCK TABLE documentation

爲了整理實現,將票價更新語句移入存儲過程,並讓票價更新和臨時表創建存儲過程循環檢查並設置鎖,執行工作,然後解鎖。

+0

它引起我注意時是否創建臨時表的使用是否正確。該存儲過程是從創建選擇fares_table(X鎖)一個不是Temptable 而另一位用戶也碰到網站做同樣的存儲過程(創建fare_tables一個臨時表), 這裏等待鎖被釋放。同時,後端需要更新一行/另一個用戶執行存儲的proc - >導致死鎖?我可以總結這些同時造成更高的死鎖機會嗎?如何使用鎖定防止這種僵局?對於請求相同鎖的其他查詢是否會影響性能? – flyclassic 2011-04-12 06:56:39

+0

也許找到沒有創建臨時表的解決方案?比您所經歷的更復雜的模式成功運行,d/b爭用少得多。重新思考模式以最大限度地選擇數據並儘量減少寫入數據。 – wallyk 2011-04-12 07:49:09

+0

我在困難的情況下,因爲我用存儲過程內部存儲過程使用加入和分組。這種方式的代碼是可重複使用和可維護的。沒有使用創建臨時表,我不能調用proc裏面的存儲過程..現在併發問題導致死鎖,如果我要從派生表連接表而不是調用過程臨時表是一個不同的故事 – flyclassic 2011-04-12 09:27:09