繼續回答星球水友提問:
沈老師,MyISAM隻支援表鎖,但網上文章卻說,在并發插入量比較大的時候,比較适合使用MyISAM,這沖突嗎? 這個問題,涉及MySQL表鎖的一些細節,借着這個問題,系統性說下表鎖的“是以然”。畫外音:網上不少文章隻說結論,不說為什麼,容易讓人蒙圈。 MySQL表鎖知識系統性梳理。 哪些存儲引擎使用表鎖?MySQL,除InnoDB支援行鎖外,MySQL的其他存儲引擎均隻使用表鎖,例如:MyISAM, MEMORY, MERGE等。 表鎖有什麼好處?(1)表鎖占用記憶體少很多,行鎖的數量與行記錄數相關,非常耗記憶體;(2)如果業務經常讀寫表中很大一部分資料時,表鎖會更快,因為此時隻涉及一個鎖,而不是同時管理N多個鎖;(3)如果業務經常使用group by,表鎖會更快,原因同(2);畫外音:這樣的一些場景,使用MyISAM比InnoDB更優。 表鎖是怎麼運作的?和其他臨界資源的讀寫鎖類似。 寫時,要加寫鎖:(1)如果表沒有鎖,對表加寫鎖;(2)否則,入寫鎖隊列; 讀時,要加讀鎖:(1)如果表沒有寫鎖,對表加讀鎖;(2)否則,入讀鎖隊列; 表鎖釋放時:如果寫鎖隊列和讀鎖隊列裡都有鎖,寫有更高的優先級,即寫鎖隊列先出列。這麼做的原因是,如果有“大查詢”,可能會導緻寫鎖被批量“餓死”,而寫鎖往往釋放很快。畫外音:潛台詞是,如果有大量并發update請求,select會等所有update請求執行完才執行。 如何檢視表鎖情況? 如果要分析表鎖沖突情況,可檢視:Table_locks_immediate:立刻獲得表鎖的次數;Table_locks_waited:需要等待表鎖的次數;這兩個變量。 使用以下指令檢視:

如果等待表鎖的次數占比較大,說明表鎖可能是潛在瓶頸。 說了半天,還是沒有講到點子上,為什麼在并發插入量比較大的時候,比較适合使用MyISAM呢?不會因為表鎖頻繁沖突而導緻吞吐量降低嗎?畫外音:知識的系統性,比問題答案更重要。 知識點一:MyISAM的索引與記錄存儲分離,有單獨的區域存儲行記錄,PK是非聚集索引。
知識點二:
MyISAM表,如果資料檔案(data file)緊密存儲,中間沒有空閑塊(free blocks),資料總是插入到資料檔案的尾部(end),就如同追加日志一樣,性能很高,此時的并發insert與select是不加鎖的(lock free)。
如上圖所示:(1)資料檔案連續且緊密的存儲着;(2)并發insert無表鎖争搶(隻需插入隊列互斥);(3)insert隻在資料檔案的尾部進行;(4)并發select也能夠同時進行(共享讀鎖); 知識點三:MyISAM表,如果資料檔案(data file)中間有空洞(hole),上述機制會失效,直到空洞被新資料填滿,又會啟用不加鎖機制。 空洞是怎麼導緻的?删除或者修改資料,都可能導緻空洞。
如上圖所示:(1)中間删除了一些資料,導緻中間出現空閑塊(free blocks);(2)此時,select和insert會有表鎖沖突,無法并發;
再如上圖所示:(1)随着插入的進行,中間的空閑塊又被填滿了;(2)此時,并發select和insert又恢複了; 結論雖然MyISAM隻支援表鎖,但高并發select與insert的業務場景,上述機制使得MyISAM的表鎖依然有非常強勁的性能。畫外音:本文基于MySQL5.6。
作業
下面哪些場景,用表鎖比行鎖性能更高。A:大部分SQL都是讀請求。B:SQL是讀寫混合,寫請求是單行的delete或update。
update t set c=xxx where unique_key=yyy;
delete from t where unique_key=zzz;
C:SQL是讀寫混合,寫請求是高并發的insert,很少有delete或update。D:SQL會掃描大量行記錄,且有很多group by。
本文轉自“架構師之路”公衆号,58沈劍提供。