鎖機制是數據庫系統區別於文件系統的一個關鍵特性,他可以確保用戶能以一致的方式讀取和修改數據。
為了保證一致性,必須有鎖的介入。MySQL操作緩沖池中的LRU列表,刪除、添加、移動LRU列表中的元素等地方也都適用鎖,從而允許對多種不同資源的並發訪問。 打個比方,我們到淘寶上買一件商品,商品只有一件庫存,這個時候如果還有另一個人買,那么如何解決是你買到還是另一個人買到的問題?
這里肯定要用到事物,我們先從庫存表中取出物品數量,然后插入訂單,付款后插入付款表信息,然后更新商品數量。在這個過程中,使用鎖可以對有限的資源進行保護,解決隔離和並發的矛盾。
MySQL的鎖管理機制:
1. Meta-data元數據鎖:在table cache緩存里實現的,為DDL(Data Definition Language)提供隔離操作。一種特別的meta-data元數據類型,叫Name Lock。(SQL層)
2. 表級table-level數據鎖(SQL層)
3. 存儲引擎特有機制 — row locks行鎖,page locks頁鎖,table locks 表級,版本控制(在引擎中實現)
4. 全局讀鎖 — FLUSH TABLES WITH READ LOCK(SQL層)
如下圖:
- 計算語句使用到的所有表
- 在每個表:打開open表 — 從table cache緩存里得到TABLE對象,並在此表
- 加上meta-data元數據鎖 等待全局讀鎖后改變數據
- 在每個表:鎖lock表 — 在表加上table-level數據鎖
- 執行語句:調用:handler::write_row()/read_rnd()/read_index(),等;隱式
- 地調用引擎級engine-level鎖機制 在每個表:釋放表的數據鎖
- 在每個表:釋放表的DDL鎖並把表放回table cache緩存里 DDL語句也是一樣,沒有典型的執行計划。
MySQL三種鎖地級別:頁級、表級、行級。
三種鎖地特性:
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。
行級鎖:開銷稍大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。
頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般。
在執行SQL語句時,會實現存儲引擎內部鎖,比如InnoDB存儲引擎的“行鎖”(MyISAM存儲引擎只支持表鎖,而InnoDB存儲引擎支持行鎖。實際上,行鎖並不總是會增加開 銷,只有當實現本身增加開銷時,行鎖才會增加開銷)。
表鎖:
手動增加表鎖: lock table XXX read(write);
釋放表鎖: unlock tables;
表級鎖性能監控:
show status like ”table%‟;
如果Table_locks_waited的值比較高,則說明存在着比較嚴重的表鎖爭用情況。
表級鎖的鎖模式:表共享讀鎖(Table Read Lock)和 表獨占寫鎖(Table Write Lock)
MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖。 所以對 MyISAM表進行操作,會有以下情況:
a、對MyISAM表的讀操作(加讀鎖),不會阻塞其他進程對同一表的讀請求,但會阻塞對同一表的寫請求。只有當讀鎖釋放后,才會執行其它進程的寫操作。
b、對MyISAM表的寫操作(加寫鎖),會阻塞其他進程對同一表的讀和寫操作,只有當寫鎖釋放后,才會執行其它進程的讀寫操作。
簡而言之,就是讀鎖會阻塞寫,但是不會堵塞讀。而寫鎖則會把讀和寫都堵塞。
關於表鎖並發插入
原則上數據表有一個讀鎖時,其它進程無法對此表進行更新操作,但在一定條件下,MyISAM表也支持查詢和插入操作的並發進行。
MyISAM存儲引擎有一個系統變量concurrent_insert,專門用以控制其並發插入的行為,其值分別可以為0、1或2。
a、當concurrent_insert設置為0時,不允許並發插入。
b、當concurrent_insert設置為1時,如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個進程讀表的同時,另一個進程從表尾插入記錄。這也 是MySQL的默認設置。
c、當concurrent_insert設置為2時,無論MyISAM表中有沒有空洞,都允許在表尾並發插入記錄。
表鎖地優化:
使用表級鎖定在鎖定實現的過程中比實現行級鎖定或頁級鎖定所帶來的附加成本要小,鎖定本身所消耗的資源也是最少的。但是由於鎖定的顆粒度比較大,所以造成鎖定資源的爭用情況也會比其他的鎖定級別都要多,從而在較大程度上會降低並發處理能力。所以表鎖優化,最關鍵的是如何讓其提高並發度。由於鎖定級別是不可能改變的了,所以首先需要盡可能地鎖定的時間變短,然后就是讓可能並發進行的操作盡可能地並發。
1.縮短鎖定時間:
1)盡量減少大的復雜的Query,將復雜的Query分拆成幾個小的Query分步進行;
2)盡可能地建立足夠高效的索引,讓數據檢索更迅速;
3)盡量讓MyISAM存儲引擎的表至存放必要的信息,控制字段類型;
4)利用合理的機會優化MyISAM表數據文件。
5)分離能並行的操作
2.合理利用上面提到的concurrent_insert
3.合理利用讀寫優先級:
MyISAM的表級鎖定對於讀和寫是有不同優先級設定的,默認情況下是寫優先級要大於讀。所以,可以根據系統環境的差異決定讀與寫的優先級。如果系統是一個以讀為主,而且要優先保證查詢性能的話,可以通過設置系統參數選項low_priority_updates=1,將寫的優先級設置為比讀低,即告訴MyISAM盡量優先處理讀請求。當然,如果系統需要優先保證數據寫入的性能的話,則不用設置low_priority_updates參數了。
參考文檔:http://www.cnblogs.com/ggjucheng/archive/2012/11/14/2770445.html
http://www.cnblogs.com/zemliu/p/3502395.html