2017-07-20 137 views
0

我在我的應用程序中有一個場景,在事務下的簡單INSERT語句阻止了MySQL中不同行上的DELETE語句,並且最終DELETE語句會話超時並出現鎖定超時錯誤。Mysql鎖定等待超時錯誤

我試圖在下面的簡單場景中解釋情況。請注意,在列上添加索引會有所幫助,但是,如果我在DELETE的WHERE子句中有2列,我仍然會看到鎖定等待超時。另請注意,在我開始交易之後,我需要做其他幾個處理,因此交易只需要幾分鐘即可提交或回滾。很難相信,即使我刪除了不同於我試圖插入的記錄,MySQL也會阻止它。

會議1: -

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation; 

+-----------------------+----------------+------------------------+ 
| @@GLOBAL.tx_isolation | @@tx_isolation | @@session.tx_isolation | 
+-----------------------+----------------+------------------------+ 
| READ-COMMITTED  | READ-COMMITTED | READ-COMMITTED   | 
+-----------------------+----------------+------------------------+ 

1 row in set (0.02 sec)` 

mysql> create table testtab(col1 int, col2 int); 
Query OK, 0 rows affected (0.53 sec) 
mysql> START TRANSACTION; 
Query OK, 0 rows affected (0.00 sec) 
mysql> INSERT INTO testtab values(1,1); 
Query OK, 1 row affected (0.00 sec) 
mysql> INSERT INTO testtab values(2,2); 
Query OK, 1 row affected (0.00 sec) 

會議2: -

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation; 
+-----------------------+----------------+------------------------+ 
| @@GLOBAL.tx_isolation | @@tx_isolation | @@session.tx_isolation | 
+-----------------------+----------------+------------------------+ 
| READ-COMMITTED  | READ-COMMITTED | READ-COMMITTED   | 
+-----------------------+----------------+------------------------+ 
1 row in set (0.00 sec) 
mysql> DELETE FROM testtab where col1=3; 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 

有什麼建議?

回答

0

這是InnoDB鎖定工作原理的結果。引用manual,

鎖定讀取,UPDATE或DELETE通常會在處理SQL語句時掃描的每個索引記錄上設置記錄鎖定。在聲明中是否存在WHERE條件將排除該行並不重要。 InnoDB不記得確切的WHERE條件,但只知道掃描了哪些索引範圍。

另外值得一提的是,

如果您有適合你的發言和MySQL必須掃描整個表來處理語句沒有索引,該表的每一行被鎖定,這反過來又塊所有由其他用戶插入到表中。創建好的索引非常重要,以便您的查詢不會不必要地掃描多行。

所以在你的情況發生什麼是兩個insert添加兩個鎖定行到表。由於沒有合適的索引,delete現在將掃描整個表格。它必須鎖定它遇到的每一行,但要做到這一點,必須等待由insert創建的鎖已被解除(這不會及時發生)。

添加上col1的索引將解決這個問題,作爲delete將只需要考慮(和鎖)的行與col1 = 3它可以找到使用索引,並且因此將具有與由其他插入的行沒有重疊交易。

如果您在爲「雙列條件」找到好索引時遇到問題,則應該添加更多關於該索引的詳細信息,可能會有適合該情況的索引。

這當然不會阻止每一種情況(例如,如果你真的想修改同一行),所以通常是一個好主意,讓交易儘可能短,準備等待那麼久和/或者如果需要準備重複交易。

這並不是InnoDB鎖定的完整描述,只是解釋您的情況的部分。

+0

感謝Solarflare。你在現場。 – DBPlayer

+0

爲類似的例子,如果我想看到阻塞查詢(顯示完整的進程列表顯示查詢只會話2),我有什麼選擇。我試過顯示引擎innodb狀態,完整的進程列表等,但似乎沒有向我展示INSERT語句,這實際上導致事務運行時間更長。 – DBPlayer

相關問題