本篇文章為大家展示了表結構怎樣變更Metadata Lock,內容簡(jiǎn)明扼要并且容易理解,絕對能使你眼前一亮,通過(guò)這篇文章的詳細介紹希望你能有所收獲。
想必玩過(guò)mysql的人對Waiting for table metadata lock肯定不會(huì )陌生,一般都是進(jìn)行alter操作時(shí)被堵住了,導致了我們在show processlist 時(shí),看到線(xiàn)程的狀態(tài)是在等metadata lock。本文會(huì )對MySQL表結構變更的Metadata Lock進(jìn)行詳細的介紹。
在線(xiàn)上進(jìn)行DDL操作時(shí),相對于其可能帶來(lái)的系統負載,其實(shí),我們最擔心的還是MDL其可能導致的阻塞問(wèn)題。
一旦DDL操作因獲取不到MDL被阻塞,后續其它針對該表的其它操作都會(huì )被阻塞。典型如下,如阻塞稍久的話(huà),我們會(huì )看到Threads_running飆升,CPU告警。
mysql> show processlist; +----+-----------------+-----------+-----------+---------+------+---------------------------------+------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-----------------+-----------+-----------+---------+------+---------------------------------+------------------------------------+ | 4 | event_scheduler | localhost | NULL | Daemon | 122 | Waiting on empty queue | NULL | | 9 | root | localhost | NULL | Sleep | 57 | | NULL | | 12 | root | localhost | employees | Query | 40 | Waiting for table metadata lock | alter table slowtech.t1 add c1 int | | 13 | root | localhost | employees | Query | 35 | Waiting for table metadata lock | select * from slowtech.t1 | | 14 | root | localhost | employees | Query | 30 | Waiting for table metadata lock | select * from slowtech.t1 | | 15 | root | localhost | employees | Query | 19 | Waiting for table metadata lock | select * from slowtech.t1 | | 16 | root | localhost | employees | Query | 10 | Waiting for table metadata lock | select * from slowtech.t1 | | 17 | root | localhost | employees | Query | 0 | starting | show processlist | +----+-----------------+-----------+-----------+---------+------+---------------------------------+------------------------------------+ rows in set (0.00 sec)
如果發(fā)生在線(xiàn)上,無(wú)疑會(huì )影響到業(yè)務(wù)。所以,一般建議將DDL操作放到業(yè)務(wù)低峰期做,其實(shí)有兩方面的考慮,1. 避免對系統負載產(chǎn)生較大影響。2. 減少DDL被阻塞的概率。
MDL引入的背景
MDL是MySQL 5.5.3引入的,主要用于解決兩個(gè)問(wèn)題,
RR事務(wù)隔離級別下不可重復讀的問(wèn)題
如下所示,演示環(huán)境,MySQL 5.5.0。
session1> begin; Query OK, 0 rows affected (0.00 sec) session1> select * from t1; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | +------+------+ rows in set (0.00 sec) session2> alter table t1 add c1 int; Query OK, 2 rows affected (0.02 sec) Records: 2 Duplicates: 0 Warnings: 0 session1> select * from t1; Empty set (0.00 sec) session1> commit; Query OK, 0 rows affected (0.00 sec) session1> select * from t1; +------+------+------+ | id | name | c1 | +------+------+------+ | 1 | a | NULL | | 2 | b | NULL | +------+------+------+ rows in set (0.00 sec)
可以看到,雖然是RR隔離級別,但在開(kāi)啟事務(wù)的情況下,第二次查詢(xún)卻沒(méi)有結果。
主從復制問(wèn)題
包括主從數據不一致,主從復制中斷等。
如下面的主從數據不一致。
session1> create table t1(id int,name varchar(10)) engine=innodb; Query OK, 0 rows affected (0.00 sec) session1> begin; Query OK, 0 rows affected (0.00 sec) session1> insert into t1 values(1,'a'); Query OK, 1 row affected (0.00 sec) session2> truncate table t1; Query OK, 0 rows affected (0.46 sec) session1> commit; Query OK, 0 rows affected (0.35 sec) session1> select * from t1; Empty set (0.00 sec)
再來(lái)看看從庫的結果
session1> select * from slowtech.t1; +------+------+------+ | id | name | c1 | +------+------+------+ | 1 | a | NULL | +------+------+------+ row in set (0.00 sec)
看看binlog的內容,可以看到,truncate操作記錄在前,insert操作記錄在后。
# at 7140 #180714 19:32:14 server id 1 end_log_pos 7261 Query thread_id=31 exec_time=0 error_code=0 SET TIMESTAMP=1531567934/*!*/; create table t1(id int,name varchar(10)) engine=innodb /*!*/; # at 7261 #180714 19:32:30 server id 1 end_log_pos 7333 Query thread_id=32 exec_time=0 error_code=0 SET TIMESTAMP=1531567950/*!*/; BEGIN /*!*/; # at 7333 #180714 19:32:30 server id 1 end_log_pos 7417 Query thread_id=32 exec_time=0 error_code=0 SET TIMESTAMP=1531567950/*!*/; truncate table t1 /*!*/; # at 7417 #180714 19:32:30 server id 1 end_log_pos 7444 Xid = 422 COMMIT/*!*/; # at 7444 #180714 19:32:34 server id 1 end_log_pos 7516 Query thread_id=31 exec_time=0 error_code=0 SET TIMESTAMP=1531567954/*!*/; BEGIN /*!*/; # at 7516 #180714 19:32:24 server id 1 end_log_pos 7611 Query thread_id=31 exec_time=0 error_code=0 SET TIMESTAMP=1531567944/*!*/; insert into t1 values(1,'a') /*!*/; # at 7611 #180714 19:32:34 server id 1 end_log_pos 7638 Xid = 421 COMMIT/*!*/;
如果會(huì )話(huà)2執行的是drop table操作,還會(huì )導致主從中斷。
有意思的是,如果會(huì )話(huà)2執行的是alter table操作,其依舊會(huì )被阻塞,阻塞時(shí)間受innodb_lock_wait_timeout參數限制。
mysql> show processlist; +----+------+-----------+----------+---------+------+-------------------+---------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+----------+---------+------+-------------------+---------------------------+ | 54 | root | localhost | NULL | Query | 0 | NULL | show processlist | | 58 | root | localhost | slowtech | Sleep | 1062 | | NULL | | 60 | root | localhost | slowtech | Query | 11 | copy to tmp table | alter table t1 add c1 int | +----+------+-----------+----------+---------+------+-------------------+---------------------------+ rows in set (0.00 sec)
MDL的基本概念
首先,看看官方的說(shuō)法,
To ensure transaction serializability, the server must not permit one session to perform a data definition language (DDL) statement on a table that is used in an uncompleted explicitly or implicitly started transaction in another session.
The server achieves this by acquiring metadata locks on tables used within a transaction and deferring release of those locks until the transaction ends.
A metadata lock on a table prevents changes to the table's structure.
This locking approach has the implication that a table that is being used by a transaction within one session cannot be used in DDL statements by other sessions until the transaction ends.
從上面的描述可以看到,
1. MDL出現的初衷就是為了保護一個(gè)處于事務(wù)中的表的結構不被修改。
2. 這里提到的事務(wù)包括兩類(lèi),顯式事務(wù)和AC-NL-RO(auto-commit non-locking read-only)事務(wù)。顯式事務(wù)包括兩類(lèi):1. 關(guān)閉AutoCommit下的操作,2. 以begin或start transaction開(kāi)始的操作。AC-NL-RO可理解為AutoCommit開(kāi)啟下的select操作。
3. MDL是事務(wù)級別的,只有在事務(wù)結束后才會(huì )釋放。在此之前,其實(shí)也有類(lèi)似的保護機制,只不過(guò)是語(yǔ)句級別的。
需要注意的是,MDL不僅僅適用于表,同樣也適用于其它對象,如下表所示,其中,"等待狀態(tài)"對應的是"show processlist"中的State。
為了提高數據庫的并發(fā)度,MDL被細分為了11種類(lèi)型。
MDL_INTENTION_EXCLUSIVE
MDL_SHARED
MDL_SHARED_HIGH_PRIO
MDL_SHARED_READ
MDL_SHARED_WRITE
MDL_SHARED_WRITE_LOW_PRIO
MDL_SHARED_UPGRADABLE
MDL_SHARED_READ_ONLY
MDL_SHARED_NO_WRITE
MDL_SHARED_NO_READ_WRITE
MDL_EXCLUSIVE
常用的有MDL_SHARED_READ,MDL_SHARE D_WRITE及MDL_EXCLUSIVE,其分別用于SELECT操作,DML操作及DDL操作。其它類(lèi)型的對應操作可參考源碼sql/mdl.h。
對于MDL_EXCLUSIVE,官方的解釋是,
/*
An exclusive metadata lock.
A connection holding this lock can modify both table's metadata and data.
No other type of metadata lock can be granted while this lock is held.
To be used for CREATE/DROP/RENAME TABLE statements and for execution of
certain phases of other DDL statements.
*/
簡(jiǎn)而言之,MDL_EXCLUSIVE是獨占鎖,在其持有期間是不允許其它類(lèi)型的MDL被授予,自然也包括SELECT和DML操作。
這也就是為什么DDL操作被阻塞時(shí),后續其它操作也會(huì )被阻塞。
關(guān)于MDL的補充
1. MDL的最大等待時(shí)間由lock_wait_timeout參數決定,其默認值為31536000(365天)。在使用工具進(jìn)行DDL操作時(shí),這個(gè)值就不太合理。事實(shí)上,pt-online-schema-change和gh-ost對其就進(jìn)行了相應的調整,其中,前者60s,后者3s。
2. 如果一個(gè)SQL語(yǔ)法上有效,但執行時(shí)報錯,如,列名不存在,其同樣會(huì )獲取MDL鎖,直到事務(wù)結束才釋放。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站