MySQL MyISAM表鎖


MyISAM存儲引擎只支持表鎖,這也是MySQL開始幾個版本中唯一支持的鎖類型。隨着應用對事務完整性和並發性要求的不斷提高,MySQL 才開始開發基於事務的存儲引擎,后來慢慢出現了支持頁鎖的BDB存儲引擎和支持行鎖的InnoDB存儲引擎。但是MyISAM的表鎖依然是使用最為廣泛的鎖類型。

 

查詢表級鎖爭用情況

show status like 'Table_locks%';

 如果Table_locks_waited的值比較高,則說明存在着較嚴重的表級鎖爭用情況。

 

MySQL表級鎖的鎖模式

MySQL的表級鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨占寫鎖(Table Write Lock)。

 對 MyISAM 表的讀操作,不會阻塞其他用戶對同一表的讀請求,但會阻塞對同一表的寫請求;對 MyISAM 表的寫操作,則會阻塞其他用戶對同一表的讀和寫操作;

 

在如表 20-2所示的例子中,當一個線程獲得對一個表的寫鎖后,只有持有鎖的線程可以對表進行更新操作。其他線程的讀、寫操作都會等待,直到鎖被釋放為止。sql如下:

 

 

 

如何加表鎖

MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程並不需要用戶干預,因此,用戶一般不需要直接用LOCK TABLE命令給MyISAM表顯式加鎖。在本文章的示例中,顯式加鎖基本上都是為了方便說明問題

Lock tables orders read local, order_detail read local;
Select sum(total) from orders;
Select sum(subtotal) from order_detail;
Unlock tables;

在LOCK TABLES時加了“local”選項,其作用就是在滿足MyISAM表並發插入條件的情況下,允許其他用戶在表尾並發插入記錄

MyISAM總是一次獲得SQL語句所需要的全部鎖。這也正是MyISAM表不會出現死鎖(DeadlockFree)的原因

 

在如表 20-3所示的例子中,一個 session使用LOCK TABLE命令給表 film_text加了讀鎖,這個session 可以查詢鎖定表中的記錄,但更新或訪問其他表都會提示錯誤;同時,另外一個session可以查詢表中的記錄,但更新就會出現鎖等待。sql如下:

 

 當使用LOCK TABLES時,不僅需要一次鎖定用到的所有表,而且,同一個表在SQL語句中出現多少次,就要通過與SQL語句中相同的別名鎖定多少次,否則也會出錯!

 

並發插入(Concurrent Inserts)

MyISAM 存儲引擎有一個系統變量 concurrent_insert,專門用以控制其並發插入的行為,其值分別可以為0、1或2。

當concurrent_insert設置為0時,不允許並發插入。

當concurrent_insert設置為1時,如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個進程讀表的同時,另一個進程從表尾插入記錄。這也是MySQL的默認設置。

當concurrent_insert設置為2時,無論MyISAM表中有沒有空洞,都允許在表尾並發插入記錄。

在如表 20-4所示的例子中,session_1獲得了一個表的READ LOCAL鎖,該線程可以對表進行查詢操作,但不能對表進行更新操作;其他的線程(session_2),雖然不能對表進行刪除和更新操作,但卻可以對該表進行並發插入操作,這里假設該表中間不存在空洞。

 

 可以利用MyISAM存儲引擎的並發插入特性來解決應用中對同一表查詢和插入的鎖爭用。例如,將concurrent_insert系統變量設為2,總是允許並發插入;同時,通過定期在系統空閑時段執行OPTIMIZE TABLE 語句來整理空間碎片,收回因刪除記錄而產生的中間空洞。

 

MyISAM的鎖調度

MySQL認為寫請求一般比讀請求要重要。這也正是MyISAM表不太適合於有大量更新操作和查詢操作應用的原因

可以通過一些設置來調節MyISAM的調度行為。

通過指定啟動參數low-priority-updates,使MyISAM引擎默認給予讀請求以優先的權利。

通過執行命令SET LOW_PRIORITY_UPDATES=1,使該連接發出的更新請求優先級降低。

通過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,降低該語句的優先級。

另外,MySQL也提供了一種折中的辦法來調節讀寫沖突,即給系統參數max_write_lock_count設置一個合適的值,當一個表的讀鎖達到這個值后,MySQL就暫時將寫請求的優先級降低,給讀進程一定獲得鎖的機會。

這里還要強調一點:一些需要長時間運行的查詢操作,也會使寫進程“餓死”!因此,應用中應盡量避免出現長時間運行的查詢操作,不要總想用一條SELECT語句來解決問題,因為這種看似巧妙的SQL語句,往往比較復雜,執行時間較長,在可能的情況下可以通過使用中間表等措施對SQL語句做一定的“分解”,使每一步查詢都能在較短時間完成,從而減少鎖沖突。如果復雜查詢不可避免,應盡量安排在數據庫空閑時段執行,比如一些定期統計可以安排在夜間執行。

 

文章來源:深入淺出MySQL-20.2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM