MySQL 啥時候用表鎖,啥時候用行鎖?

大家好,我是樹哥。

MySQL Innodb 的鎖可以說是執行引擎的併發基礎了,有了鎖才能保證數據的一致性。衆所周知,我們都知道 Innodb 有全局鎖、表級鎖、行級鎖三種,但你知道什麼時候會用表鎖,什麼時候會用行鎖嗎?雖然對 MySQL 的知識點挺熟悉的,但一開始看到這個問題,樹哥也是有點懵,我還真沒從這個角度去思考過。大家可以暫時 1 分鐘思考下答案,後面我將帶大家弄清楚這個問題。

對於這個問題,我只能粗略地想起一些片段,例如:

  1. 對於表級鎖而言,當執行 DDL 語句去修改表結構時,會使用表級鎖。
  2. 對於行級鎖而言,一般情況下都會默認使用行級鎖,貌似是需要有索引匹配到纔行。

上面就是我粗略想到的答案,不知道大家思考的答案是否和我一樣呢?下面就讓我帶着大家來溫習下 MySQL 的鎖吧!

文章思維導圖

對於數據庫而言,其鎖範圍可以分爲:

  • 全局鎖
  • 表級鎖
  • 行級鎖

全局鎖

全局鎖就是對整個數據庫實例加鎖。 MySQL 提供了一個加全局讀鎖的方法,命令是 Flush tables with read lock (FTWRL)。當你需要讓整個庫處於只讀狀態的時候,可以使用這個命令,之後其他線程的以下語句會被阻塞:數據更新語句(數據的增刪改)、數據定義語句(包括建表、修改表結構等)和更新類事務的提交語句。你可以理解爲,全局鎖基本上把數據所所有的變更語句都鎖住了。

全局鎖的典型場景應用場景是全庫邏輯備份,也就是把整個庫每個表都 select 出來存起來。上面說到全局鎖會鎖住所有變更語句,但這只是對於 MyISAM 存儲引擎而言的。對於 Innodb 而言,其可以利用 MVCC 實現數據的一致性視圖,從而不需要鎖整個庫就可以實現全庫的數據備份。

表級鎖

表級鎖可以分爲:表鎖、元數據鎖、意向鎖三種。

表鎖

表鎖,顧名思義就是對某個表加鎖。

那什麼時候會使用表鎖呢?

一般情況是對應的存儲引擎沒有行級鎖(例如:MyIASM),或者是對應的 SQL 語句沒有匹配到索引。

對於第一種情況而言,因爲對應存儲引擎不支持行鎖,所以只能是使用更粗粒度的鎖來實現,這也比較好理解。

對於第二種情況而言,如果存儲引擎支持行鎖,但對應的 SQL 就沒有使用索引,那麼此時也是會全表掃描,那此時也是會使用表鎖。例如下面的語句沒有指定查詢列,或者指定了查詢列但是並沒有用到索引,那麼也是會直接鎖定整個表。

// 沒有指定查詢列
select * from user;
// 指定查詢列,但是沒有用到索引
select * from user where name = 'zhangsan';

上面說的索引,可以說是判斷是否會用行級鎖的關鍵。但我想到一個問題:如果查詢或更新用到了索引,但是查詢或更新的數據特別多,佔全表的 80% 甚至更多,這時候是會用表鎖,還是行鎖呢? 這是一個很有意思的問題,感興趣的朋友自行弄個測試表驗證一下,後續有機會我們再聊聊這個問題。

元數據鎖

元數據,指的是我們的表結構這些元數據。元數據鎖(Metadata Lock)自然是執行 DDL 表結構變更語句時,我們對錶加上的一個鎖了。

那什麼時候會使用元數據鎖這個表級鎖呢?

當我們對一個表做增刪改查操作的時候,會加上 MDL 讀鎖;當我們要對錶結構做變更時,就會加 MDL 寫鎖。

意向鎖

意向鎖,本質上就是空間換時間的產物,是爲了提高行鎖效率的一個東西。

在 InnoDB 中,我們對某條記錄進行鎖定時,爲了提高併發度,通常都只是鎖定這一行記錄,而不是鎖定整個表。而當我們需要爲整個表加 X 鎖的時候,我們就需要遍歷整個表的記錄,如果每條記錄都沒有被加鎖,纔可以給整個表加 X 鎖。而這個遍歷過程就很費時間,這時候就有了意向鎖的誕生。

意向鎖其實就是標記這個表有沒有被鎖,如果有某條記錄被鎖住了,那麼就必須獲取該表的意向鎖。所以當我們需要判斷這個表的記錄有沒有被加鎖時,直接判斷意向鎖就可以了,減少了遍歷的時間,提高了效率,是典型的用空間換時間的做法。

那麼什麼時候會用到意向鎖呢?

很簡單,就是在對錶中的行記錄加鎖的時候,就會用到意向鎖。

行級鎖

千呼萬喚,終於來到了行級鎖。

要知道的是,行級鎖是存儲引擎級別的鎖,需要存儲引擎支持纔有效。目前 MyISAM 存儲引擎不支持行級鎖,而 Innodb 存儲引擎則支持行級鎖。而全局鎖、表級鎖,則是 MySQL 層面就支持的鎖。

那麼什麼時候會使用行級鎖呢?

當增刪改查匹配到索引時,Innodb 會使用行級鎖。

如果沒有匹配不到索引,那麼就會直接使用表級鎖。

總結

文章最後,我們回顧一下開頭提出的問題:Innodb 啥時候用表鎖,啥時候用行鎖?

表級鎖包括:表鎖、元數據鎖、意向鎖。

對於表鎖而言,當存儲引擎不支持行級鎖時,使用表鎖。SQL 語句沒有匹配到索引時,使用表鎖。

對於元數據鎖而言,對錶做增刪改查時,會加上 MDL 讀鎖。對錶結構做變更時,會加上 MDL 寫鎖。

對於意向鎖而言,對錶中的行記錄加鎖時,會用到意向鎖。

而對於行級鎖而言,增刪改查匹配到索引時,會使用行級鎖。

最後,附上本文的思維導圖,方便大家回顧本文內容~

如果你喜歡今天的分享,記得一鍵三連支持我!

文章思維導圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章