Mysql鎖機制

**

一,概述

**
表級鎖:開銷小,加鎖快;不會出現死鎖,發生鎖衝突概率高,併發度最低
行級鎖:開銷大,加鎖慢;會出現死鎖,發生鎖衝突概率最低,併發度也高
頁面鎖:開銷和加鎖介於表級和行級之間;會出現死鎖;鎖粒度介於表鎖和行鎖之間,併發度一般
表級鎖更適合於以查詢爲主,只有少量按索引條件更新數據的應用,如web運用
行級鎖則更適合於有大量按索引條件併發更新少量數據,同時又有併發查詢的運用,如在線事物處理系統

二,表級鎖定

MyISAM存儲引擎使用的鎖定機制完全是由MySql提供的表級鎖定實現

1,表級鎖的兩種模式

  • 表共享讀鎖(Table Read Lock):不會阻塞其他用戶對同一表的讀請求,但會阻塞對同一表的寫請求
  • 表獨佔寫鎖(Table Write Lock):會阻塞其他用戶對同一表的讀寫操作
    2,如何加表鎖
    MyISAM在執行查詢語句select之前,會自動給涉及的所有表加讀鎖,在執行更新操作update,delete,insert前,會自動給涉及的表加寫鎖,這個過程並不需要用戶干預,一般不需要用戶直接用Lock Table命令給MyISAM表顯示加鎖。
    3,MyISAM表鎖優化建議
    鎖本身消耗的資源最少,附加成本也是最少相對於行級鎖和頁級鎖。我們儘量讓鎖定的時間變爲最短,儘量減少併發

查詢表級鎖競爭情況

 show status like 'table%';
Table_locks_immediate	3563632234
Table_locks_waited	217
Table_open_cache_hits	0
Table_open_cache_misses	0
Table_open_cache_overflows	0

Table_locks_waited:出現表級鎖定爭用而發生等待的次數;
兩個狀態值都是從系統啓動後開始記錄,出現一次對應的事件則數量加1。如果這裏的Table_locks_waited狀態值比較高,那麼說明系統中表級鎖定爭用現象比較嚴重,就需要進一步分析爲什麼會有較多的鎖定資源爭用了。

三,行級鎖定

InnoDB鎖定模式及實現機制
共享鎖S:
排他鎖X:
意向共享鎖IS(表級鎖):
意向排他鎖IX(行級鎖):
在這裏插入圖片描述共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE 排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE

2.InnoDB行鎖實現方式
InnoDB行鎖是通過給索引上的索引項加鎖來實現的,只有通過索引條件檢索數據,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖
在實際應用中,要特別注意InnoDB行鎖的這一特性,不然的話,可能導致大量的鎖衝突,從而影響併發性能。下面通過一些實際例子來加以說明。
(1)在不通過索引條件查詢的時候,InnoDB確實使用的是表鎖,而不是行鎖。
(2)由於MySQL的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果是使用相同的索引鍵,是會出現鎖衝突的。
(3)當表有多個索引的時候,不同的事務可以使用不同的索引鎖定不同的行,另外,不論是使用主鍵索引、唯一索引或普通索引,InnoDB都會使用行鎖來對數據加鎖。
(4)即便在條件中使用了索引字段,但是否使用索引來檢索數據是由MySQL通過判斷不同執行計劃的代價來決定的,如果MySQL認爲全表掃描效率更高,比如對一些很小的表,它就不會使用索引,這種情況下InnoDB將使用表鎖,而不是行鎖。因此,在分析鎖衝突時,別忘了檢查SQL的執行計劃,以確認是否真正使用了索引。
3.間隙鎖(Next-Key鎖)
當我們用範圍條件而不是相等條件檢索數據,並請求共享或排他鎖時,InnoDB會給符合條件的已有數據記錄的索引項加鎖;
對於鍵值在條件範圍內但並不存在的記錄,叫做“間隙(GAP)”,InnoDB也會對這個“間隙”加鎖,這種鎖機制就是所謂的間隙鎖(Next-Key鎖)。
例:
假如emp表中只有101條記錄,其empid的值分別是 1,2,…,100,101,下面的SQL:

mysql> select * from emp where empid > 100 for update;
是一個範圍條件的檢索,InnoDB不僅會對符合條件的empid值爲101的記錄加鎖,也會對empid大於101(這些記錄並不存在)的“間隙”加鎖。
InnoDB使用間隙鎖的目的:
(1)防止幻讀,以滿足相關隔離級別的要求。對於上面的例子,要是不使用間隙鎖,如果其他事務插入了empid大於100的任何記錄,那麼本事務如果再次執行上述語句,就會發生幻讀;
(2)爲了滿足其恢復和複製的需要。
很顯然,在使用範圍條件檢索並鎖定記錄時,即使某些不存在的鍵值也會被無辜的鎖定,而造成在鎖定的時候無法插入鎖定鍵值範圍內的任何數據。在某些場景下這可能會對性能造成很大的危害。
除了間隙鎖給InnoDB帶來性能的負面影響之外,通過索引實現鎖定的方式還存在其他幾個較大的性能隱患:
(1)當Query無法利用索引的時候,InnoDB會放棄使用行級別鎖定而改用表級別的鎖定,造成併發性能的降低;
(2)當Query使用的索引並不包含所有過濾條件的時候,數據檢索使用到的索引鍵所只想的數據可能有部分並不屬於該Query的結果集的行列,但是也會被鎖定,因爲間隙鎖鎖定的是一個範圍,而不是具體的索引鍵;
(3)當Query在使用索引定位數據的時候,如果使用的索引鍵一樣但訪問的數據行不同的時候(索引只是過濾條件的一部分),一樣會被鎖定。
因此,在實際應用開發中,尤其是併發插入比較多的應用,我們要儘量優化業務邏輯,儘量使用相等條件來訪問更新數據,避免使用範圍條件。
還要特別說明的是,InnoDB除了通過範圍條件加鎖時使用間隙鎖外,如果使用相等條件請求給一個不存在的記錄加鎖,InnoDB也會使用間隙鎖。

6.InnoDB行鎖優化建議
InnoDB存儲引擎由於實現了行級鎖定,雖然在鎖定機制的實現方面所帶來的性能損耗可能比表級鎖定會要更高一些,但是在整體併發處理能力方面要遠遠優於MyISAM的表級鎖定的。當系統併發量較高的時候,InnoDB的整體性能和MyISAM相比就會有比較明顯的優勢了。但是,InnoDB的行級鎖定同樣也有其脆弱的一面,當我們使用不當的時候,可能會讓InnoDB的整體性能表現不僅不能比MyISAM高,甚至可能會更差。
(1)要想合理利用InnoDB的行級鎖定,做到揚長避短,我們必須做好以下工作:
a)儘可能讓所有的數據檢索都通過索引來完成,從而避免InnoDB因爲無法通過索引鍵加鎖而升級爲表級鎖定;
b)合理設計索引,讓InnoDB在索引鍵上面加鎖的時候儘可能準確,儘可能的縮小鎖定範圍,避免造成不必要的鎖定而影響其他Query的執行;
c)儘可能減少基於範圍的數據檢索過濾條件,避免因爲間隙鎖帶來的負面影響而鎖定了不該鎖定的記錄;
d)儘量控制事務的大小,減少鎖定的資源量和鎖定時間長度;
e)在業務環境允許的情況下,儘量使用較低級別的事務隔離,以減少MySQL因爲實現事務隔離級別所帶來的附加成本。
(2)由於InnoDB的行級鎖定和事務性,所以肯定會產生死鎖,下面是一些比較常用的減少死鎖產生概率的小建議:
a)類似業務模塊中,儘可能按照相同的訪問順序來訪問,防止產生死鎖;
b)在同一個事務中,儘可能做到一次鎖定所需要的所有資源,減少死鎖產生概率;
c)對於非常容易產生死鎖的業務部分,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產生的概率。
(3)可以通過檢查InnoDB_row_lock狀態變量來分析系統上的行鎖的爭奪情況:

發佈了31 篇原創文章 · 獲贊 11 · 訪問量 8593
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章