MySQL鎖(二)表鎖:為什麼給小表加欄位會導致整個庫掛掉?

大雜草發表於2020-12-16

概述

表級鎖是MySQL中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分MySQL引擎支援。最常使用的MYISAM與INNODB都支援表級鎖定。表級鎖定分為表共享讀鎖(共享鎖)與表獨佔寫鎖(排他鎖)。

特點:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖衝突的概率最高,併發度最低。

MySQL 中表級鎖有兩種:一種是表鎖,另一種是後設資料鎖(meta data lock, MDL)。

表鎖

表鎖的語法是 lock tables...read/write。與 FTWRL 類似,可以使用 unlock tables 主動釋放鎖,或者在客戶端斷開連結時自動釋放。

在還沒有出現更細粒度的鎖之前,表鎖是最常用於處理併發的。而對 InnoDB 這種支援行鎖的引擎,一般不使用 lock tables 命令來控制併發。

MDL

另一類表級的鎖是MDL。MDL不需要顯式使用,在訪問一個表的時候會被自動加上。

在MySQL 5.5版本中引入MDL,當對一個表做 CURD 時,加 MDL 讀鎖;當要對錶做 DDL 時,加 MDL 寫鎖;

  • 讀鎖之間不互斥。
  • 讀寫鎖之間、寫鎖之間互斥。

有時候給一個小表加個欄位,可能會導致整個庫掛掉。假設表 t 是一個小表。

MySQL鎖(二)表鎖:為什麼給小表加欄位會導致整個庫掛掉?
圖1 給表 t 加欄位

會話A加了 MDL 讀鎖;會話B也加了 MDL 讀鎖,可以正常執行;會話C被阻塞,等待會議A釋放 MDL 讀鎖。

如果只是會話C被阻塞倒沒關係,但之後所有在表 t 上新申請MDL 讀鎖都會被會議C阻塞。也就是這個表現在完全不能讀寫了。

如何安全地給小表加欄位?

很簡單,在 ALTER TABLE 加等待時間。如果超過等待時間後,操作回滾。

MariaDB 已經合併了 AliSQL 的這個功能,所以這兩個開源分支目前都支援 DDL NOWAIT/WAIT n 這個語法。

ALTER TABLE tbl_name NOWAIT add column ...
ALTER TABLE tbl_name WAIT N add column ... 

參考資料

相關文章