2010-05-13 88 views
2

關於在innodb中鎖定的典型文檔太混亂了。我認爲這將是很有價值的有一個「傻瓜引導的InnoDB鎖定」傻瓜指導在innodb中鎖定

我會開始,我會收集所有的響應作爲維基:

  • 列需要行之前被編入索引級別鎖定適用。
    • 示例:delete row where column1 = 10;

      所有行和索引條目:除非COLUMN1被索引

回答

2

這裏是我的筆記與MySQL支持在最近的一個,奇怪的鎖定問題工作(5.1.37版本)將鎖定表遍歷到要更改的行將被鎖定。它覆蓋在:

http://dev.mysql.com/doc/refman/5.1/en/innodb-locks-set.html

「鎖定讀,一個UPDATE或DELETE上是在SQL語句的處理掃描的每個索引記錄一般設置記錄鎖不要緊,是否有。 WHERE條件在語句中將排除該行InnoDB不記得確切的WHERE條件,但只知道掃描了哪些索引範圍...如果沒有適合您的語句的索引,並且MySQL必須掃描整個表以處理聲明中,表的每一行都被鎖定,這反過來阻止了其他用戶對該表的所有插入。「

這是一個主要的頭痛,如果屬實的話。

它是。一個常用的解決方法是:

UPDATE whichevertable設置任何東西,其中primarykey在(從可轉換的主鍵中按primarykey約束的順序);

內部選擇不需要進行鎖定,因此更新將更少地進行更新。 order by子句確保更新是以主鍵順序完成的,以匹配InnoDB的物理順序,這是實現它的最快方法。

在涉及大量行的情況下(如您的情況),最好將選擇結果存儲在添加了標誌列的臨時表中。然後從沒有設置標誌的臨時表中選擇每個批次。運行限制爲1000或10000的更新,並在更新後設置批處理標誌。限制將鎖定的數量保持在可接受的水平,而選擇工作只需要進行一次。在每批之後提交以釋放鎖。

您還可以在進行每批更新之前,通過執行未索引列的選擇總和來加速此工作。這會將數據頁面加載到緩衝池中而不鎖定。然後鎖定將持續更短的時間,因爲不會有任何磁盤讀取。

這並不總是實際可行,但當它可能會非常有幫助。如果你不能批量執行,你可以至少嘗試選擇預先加載數據,如果它足夠小以適應緩衝池。

如果可能,請使用READ COMMITTED事務隔離模式。請參閱:

http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html

要獲得減少鎖定需要使用基於行的二進制日誌(而不是基於二進制日誌的默認語句)的。

兩個已知問題:

  1. 子查詢可以小於有時理想的優化。在這種情況下,這是一個不合乎要求的依賴子查詢 - 與此案例中的替代方法相比,我提出的使用子查詢的建議結果是無益的。

  2. 刪除和更新沒有與select語句相同的查詢計劃範圍,所以有時很難在不測量結果的情況下正確優化它們以準確計算出他們正在執行的操作。

這兩個都在逐漸改善。此錯誤是一個例子,我們剛剛提高可更新的優化方案,雖然變化是顯著它仍然要通過QA,以確保它不會有什麼太大的不良影響:

http://bugs.mysql.com/bug.php?id=36569