MYSQL實戰四十五講總結筆記_07、行鎖

前言:整理歸納,僅供個人溫習之用,請支持正版極客時間

1、行鎖概念

*MySQL 的行鎖是在引擎層由各個引擎自己實現的,並不是所有的引擎都支持行鎖(比如 MyISAM 引擎)。不支持行鎖意味着併發控制只能使用表鎖,對於這種引擎的表,同一張表上任何時刻只能有一個更新在執行,這就會影響到業務併發度。

 

*行鎖就是針對數據表中行記錄的鎖。比如事務 A 更新了一行,而這時候事務 B 也要更新同一行,則必須等事務 A 的操作完成後才能進行更新。

 

2、兩階段鎖

*兩階段鎖協議:在 InnoDB 事務中,行鎖在需要的時候加上的,在事務結束時釋放。

 

*問題:在下面的操作序列中,事務 B 的 update 語句執行時會是什麼現象呢?假設字段 id 是表 t 的主鍵。

答:事務 B 的 update 語句會被阻塞,直到事務 A 執行 commit 之後,事務 B 才能繼續執行。

 

*意義:事務中需要鎖多個行,要把最可能造成鎖衝突、最可能影響併發度的鎖儘量往後放

 

3、死鎖和死鎖檢測

*死鎖:併發系統中不同線程出現循環資源依賴,涉及的線程都在等待別的線程釋放資源時,就會導致這幾個線程都進入無限等待的狀態

 

*死鎖解決策略:

  • 直接進入等待,直到超時。這個超時時間可以通過參數 innodb_lock_wait_timeout (默認50S)來設置

  • 發起死鎖檢測,發現死鎖後,主動回滾死鎖鏈條中的某一個事務,讓其他事務得以繼續執行。將參數 innodb_deadlock_detect (默認值爲on)設置爲 on,表示開啓這個邏輯。

Ps:innodb_lock_wait_timeout時間不能設置太短,比如1s,如果不是死鎖而是鎖等待,容易誤傷;

主動死鎖檢測在發生死鎖的時候,是能夠快速發現並進行處理的,但是它也是有額外負擔的。

 

*問題:所有事務都要更新同一行會發生什麼?

        每個新來的被堵住的線程,都要判斷會不會由於自己的加入導致了死鎖,這是一個時間複雜度是 O(n) 的操作。假設有 1000 個併發線程要同時更新同一行,那麼死鎖檢測操作就是 100 萬這個量級的。雖然最終檢測的結果是沒有死鎖,但是這期間要消耗大量的 CPU 資源。

 

怎麼解決由這種熱點行更新導致的性能問題?

答:1、如果能確保這個業務一定不會出現死鎖,可以臨時把死鎖檢測關掉。這種操作帶有一定的風險,因爲業務設計的時候一般不會把死鎖當做一個嚴重錯誤,畢竟出現死鎖了,就回滾,然後通過業務重試一般就沒問題了,這是業務無損的。而關掉死鎖檢測意味着可能會出現大量的超時,這是業務有損的。

2、控制併發度。併發控制要做在數據庫服務端。如果有中間件,可以考慮在中間件實現;如果團隊有能修改 MySQL 源碼的人,也可以做在 MySQL 裏面。基本思路就是,對於相同行的更新,在進入引擎之前排隊。這樣在 InnoDB 內部就不會有大量的死鎖檢測工作了。

3、設計優化:通過將一行改成邏輯上的多行來減少鎖衝突。還是以影院賬戶爲例,可以考慮放在多條記錄上,比如 10 個記錄,影院的賬戶總額等於這 10 個記錄的值的總和。這樣每次要給影院賬戶加金額的時候,隨機選其中一條記錄來加。這樣每次衝突概率變成原來的 1/10,可以減少鎖等待個數,也就減少了死鎖檢測的 CPU 消耗。

 

4、總結

*並不是每條事務執行前都會檢測死鎖,只有當所訪問的行上有鎖纔會檢測。

 

*一致性讀不會加鎖,不需要做死鎖檢測

 

*並不是每次死鎖檢測都都要掃所有事務。比如某個時刻,事務等待狀態是這樣的:B在等A,D在等C,現在來了一個E,發現E需要等D,那麼E就判斷跟D、C是否會形成死鎖,這個檢測不用管B和A

 

*如果有多種鎖,必須得“全部不互斥”才能並行,只要有一個互斥,就得等

 

*innodb行級鎖是通過鎖索引記錄實現的,如果更新的列沒建索引是會鎖住整個表的。

 

*在myisam 表上更新一行,那麼會加MDL讀鎖和表的寫鎖(先查詢後更新);然後同時另外一個線程要更新這個表上另外一行,也要加MDL讀鎖和表寫鎖。第二個線程的MDL讀鎖是能成功加上的,但是被表寫鎖堵住了。從語句現象上看,就是第二個線程要等第一個線程執行完成。

 

*如果你要刪除一個表裏面的前 10000 行數據,有以下三種方法可以做到:

第一種,直接執行 delete from T limit 10000;

第二種,在一個連接中循環執行 20 次 delete from T limit 500;

第三種,在 20 個連接中同時執行 delete from T limit 500。

你會選擇哪一種方法呢?爲什麼呢?

  • 第一種方式(即:直接執行 delete from T limit 10000)裏面,單個語句佔用時間長,鎖的時間也比較長;而且大事務還會導致主從延遲。

  • 第二種方式(即:在一個連接中循環執行 20 次 delete from T limit 500)比較好

  • 第三種方式(即:在 20 個連接中同時執行 delete from T limit 500),會人爲造成鎖衝突。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章