三分钟了解Mysql的表级锁——《深究Mysql锁》
延伸閱讀:
五分鐘了解Mysql的行級鎖
一分鐘深入Mysql的意向鎖
mysql鎖相關講解及其應用——《深究mysql鎖》了解鎖前,一定要先看這篇,了解什么是MVCC,如果我們學習鎖,沒有MVCC的知識,理解起來會總覺得不明朗。本來我的這個只是個記錄,并不是專門的講給別人看的,后發現有不少人看,我還是專門加上這篇文章的鏈接。
我們首先需要知道的一個大前提是:mysql的鎖是由具體的存儲引擎實現的。所以像Mysql的默認引擎MyISAM和第三方插件引擎 InnoDB的鎖實現機制是有區別的。可根據不同的場景選用不同的鎖定機制。
Mysql有三種級別的鎖定:表級鎖定、頁級鎖定、行級鎖定
一、定義
- 每次鎖定的是一張表的鎖機制就是表級別鎖定(table-level)。它是MySQL各存儲引擎中粒度最大的鎖定機制。
二、優缺點
1. 優點
- 實現邏輯簡單,開銷小。
- 獲取鎖和釋放鎖的速度快。
- 由于表級鎖一次會將整個表鎖定,所以能很好的避免死鎖問題。
2. 缺點
- 由于鎖粒度最大,因此出現爭用被鎖定資源的概率也會最高,致使并發度十分低下。
三、支持存儲引擎
- 使用表級鎖定的主要有MyISAM,MEMORY,CSV等一些非事務性存儲引擎。
四、表級鎖類型
MySQL的表級鎖有兩種類型:表共享讀鎖(Table Read Lock)和表獨占寫鎖(Table Write Lock)。
鎖模式的兼容性:
- 對MyISAM表的讀操作,不會阻塞其他用戶對同一表的讀請求,但會阻塞對同一表的寫操作;
- 對MyISAM表的寫操作,則會阻塞其他用戶對同一表的讀和寫操作;
MyISAM表的讀操作與寫操作之間,以及寫操作之間是串行的。當一個線程獲得對一個表的寫鎖后,只有持有鎖的線程可以對表進行更新操作。其他線程的讀、寫操作都會等待,直到鎖被釋放為止。
五、如何加表鎖
-
在執行查詢語句(select)前,會自動給涉及的所有表加讀鎖
-
在執行更新操作(update、delete、insert等)前,會自動給涉及的表加寫鎖。這個過程并不需要用戶干預,因此不需要直接用lock table命令給MyISAM表顯式加鎖。
顯示加寫鎖:
// 當一個線程獲得對一個表的寫鎖后,只有持有鎖的線程可以對表進行更新操作。 // 其他線程的讀、寫操作都會等待,直到鎖被釋放為止。 // test表將會被鎖住,另一個線程執行select * from test where id = 3;將會一直等待,直到test表解鎖 LOCK TABLE test WRITE;顯示加讀鎖
// test表將會被鎖住,另一個線程執行select * from test where id = 3;不會等待 // 執行UPDATE test set name='peter' WHERE id = 4;將會一直等侍,直到test表解鎖 LOCK table test READ;顯示釋放鎖:
UNLOCK TABLES;需要注意的是,在同一個SQL session里,如果已經獲取了一個表的鎖定,則對沒有鎖的表不能進行任何操作,否則會報錯。
// 鎖定test表 LOCK table test WRITE;// 操作鎖定表沒問題 SELECT * from test where id = 4;// 操作沒有鎖的表會報錯 SELECT * from bas_farm where id =1356報錯:[Err] 1100 - Table 'bas_farm' was not locked with LOCK TABLES。這是因為MyISAM希望一次獲得sql語句所需要的全部鎖。這也正是myisam表不會出現死鎖的原因。
當然,你也不必擔心,MyISAM引擎的默認方式是會給同一個session里的所有表都加上鎖的,不會麻煩你自己顯示操作的。
六、查看表級鎖爭用情況
執行:show status like ‘table%’;
mysql> show status like 'table%'; +----------------------------+-----------+ | Variable_name | Value | +----------------------------+-----------+ | Table_locks_immediate | 20708 | | Table_locks_waited | 0 | +----------------------------+-----------+Table_locks_immediate:產生表級鎖定的次數;
Table_locks_waited:出現表級鎖定爭用而發生等待的次數;
如果Table_locks_waited狀態值比較高,那么說明系統中表級鎖定爭用現象比較嚴重,就需要進一步分析為什么會有較多的鎖定資源爭用了。
七、優化表級鎖定
優化表級鎖時的最大問題是:提高并發度
###1. 通過減少查詢時間縮短鎖定時間
縮短鎖定時間的總體原則是:讓Query執行時間盡可能的短。
-
盡量減少大的、復雜的Query,將復雜Query分拆成幾個小的Query分步執行;
-
盡可能的建立足夠高效的索引,讓數據檢索更迅速;
-
盡量讓MyISAM存儲引擎的表只存放必要的信息,控制字段類型;
-
利用合適的機會優化MyISAM表數據文件。
###2. 設置可并發插入:concurrent_insert=2
MyISAM的表鎖雖是讀寫互相阻塞的,但依然能夠實現并行操作。MyISAM存儲引擎有一個控制是否打開Concurrent Insert(并發插入)功能的參數選項:concurrent_insert,取值范圍為0,1,2。 -
concurrent_insert=0,不允許并發插入。
-
concurrent_insert=1,如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個線程讀表的同時,另一個線程從表尾插入記錄。這是MySQL的默認設置;
-
concurrent_insert=2,無論MyISAM表中有沒有空洞,都允許在表尾并發插入記錄;
所以,我們可通過設置concurrent_insert=2,同時定期在系統空閑時段執行optimize table tableName語句來整理空間碎片,收回因刪除記錄而沒有真正釋放的空間,從而提高并發。optimize參考:mysql中OPTIMIZE TABLE的作用及使用
###3. 合理設置讀寫優先級
MyISAM存儲引擎默認是寫優先級大于讀優先級。即使是寫請求后到,寫鎖也會插到讀鎖請求之前。
但是,有時像修改文章點擊數 操作是不那么重要的,我們希望的是讀更快,此時我們可以這樣:
UPDATE LOW_PRIORITY article SET click_num=134 WHERE id = 823LOW_PRIORITY使得系統認為update操作優化級比讀操作低,如果同時出現讀操作和上面的更新操作,則優先執行讀操作。
MySQL提供了幾個語句調節符,允許你修改它的調度策略:
-
LOW_PRIORITY關鍵字應用于:DELETE、INSERT、LOAD DATA、REPLACE和UPDATE。
-
HIGH_PRIORITY關鍵字應用于:SELECT、INSERT語句。
-
delayed(延遲)關鍵字應用于:INSERT、REPLACE語句。
如果你希望所有支持LOW_PRIORITY選項的語句都默認地按照低優先級來處理,那么可能使用**low-priority-updates**選項來啟動服務器。然后可通過使用insert HIGH_PRIORITY table.....來把個別我們希望的INSERT語句提高到正常的寫入優先級。
總結
以上是生活随笔為你收集整理的三分钟了解Mysql的表级锁——《深究Mysql锁》的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么样的编程姿势才没有bug
- 下一篇: 五分钟了解Mysql的行级锁——《深究M