MDL是在5.5才引入到mysql,之前也有類似保護元數據的機制,只是沒有明確提出MDL概念而已。但是5.5之前版本(比如5.1)與5.5之后版本在保護元數據這塊有一個顯著的不同點是,5.1對于元數據的保護是語句級別的,5.5對于metadata的保護是事務級別的。所謂語句級別,即語句執行完成后,無論事務是否提交或回滾,其表結構可以被其他會話更新;而事務級別則是在事務結束后才釋放MDL。
引入MDL后,主要解決了2個問題,一個是事務隔離問題,比如在可重復隔離級別下,會話A在2次查詢期間,會話B對表結構做了修改,兩次查詢結果就會不一致,無法滿足可重復讀的要求;另外一個是數據復制的問題,比如會話A執行了多條更新語句期間,另外一個會話B做了表結構變更并且先提交,就會導致slave在重做時,先重做alter,再重做update時就會出現復制錯誤的現象。
5.5以后,什么情況下會碰到MDL鎖,我結合實際情況舉3個會出現MDL的場景,來分析MDL加鎖時機。下文的.測試都是以mysql 5.5這個版本為基準,沒有考慮到online ddl,下一篇博文會詳細介紹5.6的online ddl。
1.大查詢或mysqldump導致alter等待MDL
時間點 | 會話A | 會話B | 會話C |
1 | Select count(*) from t; | ||
2 | alter table t add column c3 int;阻塞 | ||
3 | Show processlist; B:Waiting for table metadata lock | ||
4 | A:執行完畢 | ||
5 | Show processlist; B:copy to tmp table | ||
6 | B:繼續執行 | ||
7 | Select count(*) from t; | ||
8 | Show processlist; A: Sending data B: copy to tmp table | ||
9 | A:執行完畢 |
表1
從表1可以看到,會話A先執行select ,B后執行alter,在會話A執行完畢前,會話B拿不到MDL鎖。A會話在時間點4執行完畢后,會話B拿到MDL鎖,變為copy to tmp table狀態,時間點7,A會話再次執行查詢,此時A和B都正常執行,這說明對于MDL鎖而言,select會阻塞alter,而alter不會阻塞select。
2.表上存在未提交的事務,導致alter等待MDL
時間點 | 會話A | 會話B | 會話C |
1 | set autocommit=0; update t set c2='9999' where c1=4; | ||
2 | alter table t drop column c3; | ||
3 | Show processlist; B:Waiting for table metadata lock | ||
4 | A:提交事務 commit | ||
5 | Show processlist; B:copy to tmp table | ||
6 | B:繼續執行 | ||
7 | update t set c2='9999' where c1=4;阻塞 | ||
8 | Show processlist; A: Waiting for table metadata lock B: copy to tmp table | ||
9 | B執行完畢 | ||
10 | A執行完畢 |
表2
從表2可以看到,會話A第一次執行update語句后,未提交,導致后面會話B執行alter語句時需要等待MDL鎖;時間點4,A會話提交事務,此時會話B獲取MDL鎖,開始執行;時間點7,A會話再次發起update操作,此時A會話被阻塞住,這說明對于MDL鎖而言,update會阻塞alter,同樣alter也會阻塞update。
PS:時間點3由于通過show processlist只看到alter被阻塞了,但不清楚被誰阻塞,可以通過查看information_schema.innodb_trx可以找到活動的事務。
3.這種情況是第1種情況的特例,存在一個查詢失敗的語句,比如查詢不存在的列,語句失敗返回,但是事務沒有提交,此時alter仍然會被堵住。
時間點 | 會話A | 會話B | 會話C |
1 | Start transaction; Select c99 from t; Unknown column 'c99' in 'field list' | ||
2 | alter table t drop column c3; | ||
3 | Show processlist; B:copy to tmp table | ||
4 | Show processlist; B:Waiting for table metadata lock | ||
5 | A:提交事務 commit | ||
6 | 執行完畢 |
表3
這里注意時間1,會話A要顯示開啟一個事務,否則查詢會隱式回滾結束,無法重現上面的場景。會話B執行alter后,沒有立即阻塞住,而是立馬開始copy to tmp table,這個過程結束后,才進行了MDL鎖等待。這怎么解釋呢,應該是執行alter操作主要分為創建臨時新表->插入老表的數據->臨時新表rename to老表三個步驟,在這種情況下,到最后一步才需要MDL鎖,所以copy過程中不會阻塞。由于沒有查詢在進行,而且查詢也沒有進入innodb層 (失敗返回),所以show processlist和information_schema.innodb_trx沒有可以參考的信息。
這里有一個小疑點,對于第一種和第二種情況,alter在開始時就立馬堵住了,第三種情況是copy結束后,才堵住。我猜測alter內部會根據實際情況,確定什么時候上MDL鎖,有興趣的同學可以去debug源碼看看究竟。
參考:
http://www.mysqlperformanceblog.com/2013/02/01/implications-of-metadata-locking-changes-in-mysql-5-5/
http://ctripmysqldba.iteye.com/blog/1938150
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com