關於MySQL建表對DML的影響
今天一位同學問到線上曾經碰到過連續建表,導致阻塞普通的insert、update等。不過也沒有保留現場。因此有疑問為什麼建表會影響DML?
分析
首先這個現象不是在所有場景都會碰到(否則MySQL的使用者們早就跳起來了)。
一來建表這個操作本身很快,只涉及到寫表定義檔案和初始化表空間。中間涉及到redo和undo的操作也很少(這裡只討論InnoDB表)。因此除非碰到磁碟IO響應不了,否則多數情況下建表操作很快結束,不會“穩定復現”
二來即使由於io原因,建表過程執行時間較長,建表操作也不會阻塞一些DML操作。
因此只能從程式碼出發看衝突的case。
假設session 1正在執行一個create table操作,且由於io原因阻塞在寫表空間檔案這個步驟上。討論session2作如下操作的場景。
無主鍵表insert
此時insert操作由於需要申請系統自增主鍵,需要對dict_sys->mutex加鎖。而這個鎖需要等session1建表操作完成後才釋放,因此出現等待。
有外來鍵表的操作
此時session2需要判斷外來鍵一致性,需要對dict_sys->mutex加鎖。
這裡包含幾個方面:外來鍵約束的child表插入資料時和parent表刪除資料時,已經這兩個表的關聯外來鍵欄位被修改時,均會觸發等待。
有同學會說我們線上這兩種情況都禁止了,是不是就不會因為這個鎖的原因導致阻塞dml?
新開啟表時
若這個insert操作需要新開啟一個表時,需要根據表名從字典中取出資訊,也會觸發等待。
即使原來已經開啟過的表,也會因為執行了flush table或者表空間淘汰而要求下次訪問需要重新開啟。
影響的其他操作
順著dict_sys->mutex我們還可以發現有以下幾個操作,若發生在session2,都會被阻塞
1) 1) Flush tables
2) select * from information_schema.tables;
2) 以上兩個因為都要訪問到表物件列表,還比較好理解
3) select * from information_schema.innodb_sys_tables;
3)實際上可以用另外一個鎖來單獨處理sys_tables
4) show create table another_table
這個是因為必須判斷是否有外來鍵關聯
簡單留個問題:為什麼show tables並不會被阻塞?