# 使用show processlist語(yǔ)句查看會(huì)話狀態(tài)信息,發(fā)現(xiàn)DDL語(yǔ)句的state列值為Waiting for table metadata lock,表示在等待MDL元數(shù)據(jù)鎖。根據(jù)MySQL 5.7及其之后的版本中的online ddl特性,該語(yǔ)句應(yīng)該立即執(zhí)行完成(它只會(huì)修改元數(shù),因?yàn)檫@里只是修改了字段長(zhǎng)度,并沒有修改字段的其他屬性),因此,故障現(xiàn)象確認(rèn) admin@localhost : (none) 11:48:22> show processlist; +----+-------+-----------+--------+---------+------+---------------------------------+-----------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-------+-----------+--------+---------+------+---------------------------------+-----------------------------+ | 27 | admin | localhost | sbtest | Sleep | 123 | | NULL | | 28 | admin | localhost | sbtest | Query | 102 | Waiting for table metadata lock | alter table sbtest1 modify column `pad` varchar(70) COLLATE utf8_bin NOT NULL DEFAULT '' | | 29 | admin | localhost | NULL | Query | 0 | starting | show processlist | | 30 | admin | localhost | NULL | Sleep | 93 | | NULL | +----+-------+-----------+--------+---------+------+---------------------------------+-------------------------------+ 4 rows in set (0.00 sec)
首先,我們查看主機(jī)負(fù)載信息,通過下圖我們可以看到,主機(jī)基本處于空載狀態(tài),毫無壓力
目前創(chuàng)新互聯(lián)公司已為上千余家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬主機(jī)、網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計(jì)、資溪網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。然后,我們查看數(shù)據(jù)庫(kù)的活躍會(huì)話數(shù)量及其狀態(tài),我們可以看到數(shù)據(jù)庫(kù)中并沒有大量會(huì)話,也不存在正在執(zhí)行的DML語(yǔ)句在操作表sbtest1,也不存在同時(shí)有其他會(huì)話同時(shí)使用DDL在操作相同的表,但這里無法確認(rèn)是否存在未提交的事務(wù)
# 反復(fù)多執(zhí)行幾次show processlist語(yǔ)句 admin@localhost : (none) 11:49:10> show processlist; +----+-------+-----------+--------+---------+------+---------------------------------+-----------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-------+-----------+--------+---------+------+---------------------------------+------------------------------------+ | 27 | admin | localhost | sbtest | Sleep | 149 | | NULL | | 28 | admin | localhost | sbtest | Query | 128 | Waiting for table metadata lock | alter table sbtest1 modify column `pad` varchar(70) COLLATE utf8_bin NOT NULL DEFAULT '' | | 29 | admin | localhost | NULL | Query | 0 | starting | show processlist | | 30 | admin | localhost | NULL | Sleep | 119 | | NULL | +----+-------+-----------+--------+---------+------+---------------------------------+---------------------------------------+ 4 rows in set (0.00 sec)
先查看information_schema中記錄的事務(wù)信息
# 發(fā)現(xiàn)并沒有事務(wù)存在... admin@localhost : sbtest 05:49:17> select * from information_schema.innodb_trx\G Empty set (0.00 sec) # 也可以順便使用sys.innodb_lock_waits視圖確認(rèn)是否存在一些事務(wù)鎖等待 admin@localhost : performance_schema 06:27:35> select * from sys.innodb_lock_waits\G Empty set, 3 warnings (0.00 sec) # 查詢結(jié)果為空 查看performance_schema下的MDL元數(shù)據(jù)鎖記錄信息 # WTF..居然為空 admin@localhost : sbtest 06:00:21> select * from performance_schema.metadata_locks; Empty set (0.00 sec) # 也可以順便使用sys.schema_table_lock_waits視圖查看表級(jí)別的鎖等待 admin@localhost : performance_schema 06:28:12> select * from sys.schema_table_lock_waits\G Empty set (0.00 sec) # 查詢結(jié)果為空
查看performance_schema下的handle持有信息
# 發(fā)現(xiàn)表sbtest1的handle被thread_id=70的線程持有 admin@localhost : (none) 11:49:36> select * from performance_schema.table_handles where OWNER_THREAD_ID!=0; +-------------+---------------+-------------+--------+-----------------+----------------+---------------+---------------+ | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | OBJECT_INSTANCE_BEGIN | OWNER_THREAD_ID | OWNER_EVENT_ID | INTERNAL_LOCK | EXTERNAL_LOCK | +-------------+---------------+-------------+---------+-----------------+----------------+---------------+---------------+ | TABLE | sbtest | sbtest1 | 140049018564288 | 70 | 6 | NULL | NULL | +-------------+---------------+-------------+----------+-----------------+----------------+---------------+---------------+ 1 row in set (0.00 sec) # 通過performance_schema.threads表查看是哪個(gè)線程(thread_id是數(shù)據(jù)庫(kù)內(nèi)部的線程ID,我們需要看到與之對(duì)應(yīng)的processlist id) admin@localhost : (none) 11:50:03> select thread_id,processlist_id,type from performance_schema.threads where processlist_id is not null and type='FOREGROUND'; +-----------+----------------+------------+ | thread_id | processlist_id | type | +-----------+----------------+------------+ | 43 | 1 | FOREGROUND | | 69 | 27 | FOREGROUND | | 70 | 28 | FOREGROUND | # 發(fā)現(xiàn)processlist id為28 | 71 | 29 | FOREGROUND | | 72 | 30 | FOREGROUND | +-----------+----------------+------------+ 5 rows in set (0.00 sec) # 通過show processlist再次查看一下id號(hào),額。。發(fā)現(xiàn)id列為28的居然就是執(zhí)行DDL語(yǔ)句被hang住那個(gè)會(huì)話,好吧,白忙活了 admin@localhost : (none) 11:50:26> show processlist; +----+-------+-----------+--------+---------+------+---------------------------------+------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-------+-----------+--------+---------+------+---------------------------------+--------------------------------------+ | 27 | admin | localhost | sbtest | Sleep | 228 | | NULL | | 28 | admin | localhost | sbtest | Query | 207 | Waiting for table metadata lock | alter table sbtest1 modify column `pad` varchar(70) COLLATE utf8_bin NOT NULL DEFAULT '' | | 29 | admin | localhost | NULL | Query | 0 | starting | show processlist | | 30 | admin | localhost | NULL | Sleep | 198 | | NULL | +----+-------+-----------+--------+---------+------+---------------------------------+-----------------------------------------+ 4 rows in set (0.00 sec)
通過show engine innodb status查看下鎖與事務(wù)信息
# 仍然沒有發(fā)現(xiàn)有效的鎖信息 admin@localhost : performance_schema 06:14:13> show engine innodb status; ...... ------------ TRANSACTIONS ------------ Trx id counter 11559 Purge done for trx's n:o < 11557 undo n:o < 0 state: running but idle History list length 60 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 421628104988048, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421628104987136, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421628104985312, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421628104984400, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421628104986224, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ......
排查到這里,視乎已經(jīng)沒招了,也許我們還可以用mysqladmin debug命令試試看
# 執(zhí)行debug命令,執(zhí)行該命令之后,一些鎖信息可能會(huì)被debug出來打印到錯(cuò)誤日志中 [root@physical-machine ~]# mysqladmin debug # 很遺憾,在錯(cuò)誤日志中仍然沒有發(fā)現(xiàn)有效的鎖信息 [root@physical-machine ~]# vim /data/mysqldata1/log/error.log
等等,我們好像忽略了點(diǎn)什么,既然DDL語(yǔ)句在等待MDL元數(shù)據(jù)鎖,為啥在performance_schema.metadata_locks表中沒有記錄?查看一下MDL事件采集器試試看?
# 喔。。發(fā)現(xiàn)居然MDL鎖信息的采集器開關(guān)并沒有打開,難怪metadata_locks表中無法記錄MDL元數(shù)據(jù)鎖信息 admin@localhost : performance_schema 06:30:16> select * from performance_schema.setup_instruments where name like '%/mdl'; +----------------------------+---------+-------+ | NAME | ENABLED | TIMED | +----------------------------+---------+-------+ | wait/lock/metadata/sql/mdl | NO | NO | +----------------------------+---------+-------+ 1 row in set (0.00 sec) # 現(xiàn)在,我們啟用mdl的采集器 admin@localhost : sbtest 07:18:52> call sys.ps_setup_enable_instrument('sql/mdl'); +-----------------------+ | summary | +-----------------------+ | Enabled 6 instruments | +-----------------------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec)
然后,我們重新查詢information_schema下的事務(wù)和鎖信息
# 查看information_schema.innodb_trx表,仍然沒有事務(wù)信息 admin@localhost : sbtest 07:17:03> select * from information_schema.innodb_trx\G Empty set (0.00 sec) # 查看事務(wù)鎖等待信息,仍然為空 admin@localhost : sbtest 07:17:30> select * from sys.innodb_lock_waits\G Empty set, 3 warnings (0.01 sec)
查看performance_schema下的MDL元數(shù)據(jù)鎖記錄信息
# 查看metadata_locks表中的MDL鎖信息,咦,有信息了!不過,有點(diǎn)亂?。ㄎ覀冞@里只查詢sbtest庫(kù)下的sbtest1表就可以了,因?yàn)槲覀兊牟僮饕仓簧婕暗竭@張表) admin@localhost : (none) 11:52:46> select * from performance_schema.metadata_locks where OBJECT_SCHEMA='sbtest' and OBJECT_NAME='sbtest1'; +-------------+---------------+-------------+-----+--------+---------------+-------------+--------+-----------------+----------------+ | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID | +-------------+---------------+-------------+-----+--------+---------------+-------------+--------+-----------------+----------------+ # 從這行信息我們可以看到,表sbtest1上有一把SHARED_WRITE鎖處于GRANTED狀態(tài),為thread_id=69的線程所持有。SHARED_WRITE類型的MDL鎖是一把意向排他IX鎖,通常在執(zhí)行MDL或select ... for update時(shí)產(chǎn)生 | TABLE | sbtest | sbtest1 | 140048817276288 | SHARED_WRITE | TRANSACTION | GRANTED | | 69 | 11 | # 從這行信息我們可以看到,表sbtest1上有一把SHARED_UPGRADABLE的鎖處于GRANTED狀態(tài),為thread_id=70的線程持有,從上文中的信息我們可以知道,thread_id=70的process id為28,也就是執(zhí)行DDL語(yǔ)句被阻塞的那個(gè)會(huì)話id。SHARED_UPGRADABLE類型的MDL鎖是一把共享升級(jí)鎖,一般在執(zhí)行online DDL語(yǔ)句時(shí)會(huì)產(chǎn)生。它的作用是在執(zhí)行online ddl期間允許相同表的DML但防止DDL | TABLE | sbtest | sbtest1 | 140049018604784 | SHARED_UPGRADABLE | TRANSACTION | GRANTED | | 70 | 6 | # 從這行信息我們可以看到,表sbtest1上有一把EXCLUSIVE處于PENDING狀態(tài),為thread_id=70的線程在等待,從上文中的信息我們可以知道,thread_id=70的process id為28,也就是執(zhí)行DDL語(yǔ)句被阻塞的那個(gè)會(huì)話id。EXCLUSIVE類型的MDL鎖是一把排它X鎖,用于阻止其他線程讀寫元數(shù)據(jù)信息,一般在執(zhí)行DDL時(shí)產(chǎn)生 | TABLE | sbtest | sbtest1 | 140049018564112 | EXCLUSIVE | TRANSACTION | PENDING | | 70 | 6 | +-------------+---------------+-------------+-----+---------+---------------+-------------+--------+-----------------+----------------+ 3 rows in set (0.00 sec) # 通過上述信息我們可以得知,thread_id=70的線程需要獲取的EXCLUSIVE鎖與thread_id=69的線程所持有的SHARED_WRITE鎖沖突了,但thread_id=69線程的process id是多少呢?查看一下performance_schema.threads表 admin@localhost : (none) 11:53:47> select thread_id,processlist_id,type from performance_schema.threads where processlist_id is not null and type='FOREGROUND'; +-----------+----------------+------------+ | thread_id | processlist_id | type | +-----------+----------------+------------+ | 43 | 1 | FOREGROUND | | 69 | 27 | FOREGROUND | # 發(fā)現(xiàn)thread_id=69的線程process id為27 | 70 | 28 | FOREGROUND | | 71 | 29 | FOREGROUND | | 74 | 32 | FOREGROUND | +-----------+----------------+------------+ 5 rows in set (0.01 sec) # 到這里,我們知道了DDL語(yǔ)句就是被process id為27的線程阻塞的,但,還不是很直觀,查看起來比較繁瑣,我們還是直接使用sys.schema_table_lock_waits視圖查看表級(jí)別的鎖等待試試看吧,可以發(fā)現(xiàn),該視圖打印的信息看起來就很清晰了(可以清晰看到誰(shuí)在等待,誰(shuí)持有鎖),不過,怎么有兩行?以哪行為準(zhǔn)呢? admin@localhost : (none) 11:59:04> select * from sys.schema_table_lock_waits\G *************************** 1. row *************************** object_schema: sbtest object_name: sbtest1 waiting_thread_id: 70 waiting_pid: 28 waiting_account: admin@localhost waiting_lock_type: EXCLUSIVE waiting_lock_duration: TRANSACTION waiting_query: alter table sbtest1 modify col ... E utf8_bin NOT NULL DEFAULT '' waiting_query_secs: 744 waiting_query_rows_affected: 0 waiting_query_rows_examined: 0 blocking_thread_id: 69 blocking_pid: 27 blocking_account: admin@localhost blocking_lock_type: SHARED_WRITE blocking_lock_duration: TRANSACTION sql_kill_blocking_query: KILL QUERY 27 # 這一行表鎖等待信息提示kill 掉process id為27的線程 sql_kill_blocking_connection: KILL 27 *************************** 2. row *************************** object_schema: sbtest object_name: sbtest1 waiting_thread_id: 70 waiting_pid: 28 waiting_account: admin@localhost waiting_lock_type: EXCLUSIVE waiting_lock_duration: TRANSACTION waiting_query: alter table sbtest1 modify col ... E utf8_bin NOT NULL DEFAULT '' waiting_query_secs: 744 waiting_query_rows_affected: 0 waiting_query_rows_examined: 0 blocking_thread_id: 70 blocking_pid: 28 blocking_account: admin@localhost blocking_lock_type: SHARED_UPGRADABLE blocking_lock_duration: TRANSACTION sql_kill_blocking_query: KILL QUERY 28 # 這一行表鎖等待信息提示kill 掉process id為28的線程 sql_kill_blocking_connection: KILL 28 2 rows in set (0.01 sec)
DBA側(cè)可通過在執(zhí)行DDL語(yǔ)句的會(huì)話中,會(huì)話級(jí)別設(shè)置lock_wait_timeout系統(tǒng)變量為一個(gè)較小的值,在超過該時(shí)間值之后,仍然無法獲得所需的鎖時(shí),自動(dòng)放棄DDL操作(請(qǐng)自行評(píng)估需求)
root@localhost : sbtest 04:37:43> set lock_wait_timeout=10; Query OK, 0 rows affected (0.00 sec) root@localhost : sbtest 04:37:47> alter table sbtest1 modify column `pad` varchar(70) COLLATE utf8_bin NOT NULL DEFAULT ''; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
2)在會(huì)話1中,開啟一個(gè)顯式事務(wù),并使用INSERT語(yǔ)句插入一行超過字段定義長(zhǎng)度的數(shù)據(jù)行(模擬應(yīng)用側(cè)插入數(shù)據(jù))
admin@localhost : sbtest:13: > begin; Query OK, 0 rows affected (0.00 sec) admin@localhost : sbtest:17: > insert into sbtest1 values(2,2,'40393031789-25132409365-58213491013-66541287984-65586459874-05762316127-59922091522-12151119251-49498591378-18011532520','test-29736863337-73672352543-26439979097-89323822066-87557735686'); ERROR 1406 (22001): Data too long for column 'pad' at row 1
3)在會(huì)話2中,將報(bào)錯(cuò)字段pad的長(zhǎng)度加長(zhǎng)到70個(gè)字符(模擬DBA側(cè)使用DDL語(yǔ)句修改列長(zhǎng)度定義)
# 查看表結(jié)構(gòu)中的字段定義長(zhǎng)度,可以發(fā)現(xiàn),報(bào)錯(cuò)的pad列定義長(zhǎng)度為varchar類型的60個(gè)字符長(zhǎng)度 root@localhost : sbtest 04:12:03> show create table sbtest1; +---------+------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------+-------------------------------------------------------------------------------------------------------+ | sbtest1 | CREATE TABLE `sbtest1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `k` int(11) NOT NULL DEFAULT '0', `c` char(120) COLLATE utf8_bin NOT NULL DEFAULT '', `pad` varchar(60) COLLATE utf8_bin NOT NULL DEFAULT '', # pad字段的定義長(zhǎng)度為60 PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=20000001 DEFAULT CHARSET=utf8 COLLATE=utf8_bin | +---------+-------------------------------------------------------------------------------------------------------+ 1 row in set (0.01 sec) # 查看INSERT語(yǔ)句中,pad列給出數(shù)據(jù)字符串的字符長(zhǎng)度與字節(jié)長(zhǎng)度 ## INSERT語(yǔ)句中給出的pad列值字符長(zhǎng)度為64 root@localhost : sbtest 11:01:33> select char_length('test-29736863337-73672352543-26439979097-89323822066-87557735686'); +---------------------------------------------------------------------------------+ | char_length('test-29736863337-73672352543-26439979097-89323822066-87557735686') | +---------------------------------------------------------------------------------+ | 64 | +---------------------------------------------------------------------------------+ 1 row in set (0.00 sec) ## INSERT語(yǔ)句中給出的pad列值字節(jié)長(zhǎng)度為64 root@localhost : sbtest 11:02:19> select length('test-29736863337-73672352543-26439979097-89323822066-87557735686'); +----------------------------------------------------------------------------+ | length('test-29736863337-73672352543-26439979097-89323822066-87557735686') | +----------------------------------------------------------------------------+ | 64 | +----------------------------------------------------------------------------+ 1 row in set (0.00 sec) # 使用alter語(yǔ)句修改pad列定義長(zhǎng)度為70 root@localhost : sbtest 04:12:47> alter table sbtest1 modify column `pad` varchar(70) COLLATE utf8_bin NOT NULL DEFAULT ''; ## 發(fā)生阻塞
4)在會(huì)話3中,查看數(shù)據(jù)庫(kù)中的會(huì)話狀態(tài)信息(模擬DBA側(cè)排查故障問題)
# 可以看到info列的alter語(yǔ)句的state列值為Waiting for table metadata lock,表示在等待MDL鎖 admin@localhost : (none) 11:50:55> show processlist; +----+-------+-----------+--------+---------+------+---------------------------------+--------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-------+-----------+--------+---------+------+---------------------------------+--------------------------------+ | 27 | admin | localhost | sbtest | Sleep | 919 | | NULL | | 28 | admin | localhost | sbtest | Query | 898 | Waiting for table metadata lock | alter table sbtest1 modify column `pad` varchar(70) COLLATE utf8_bin NOT NULL DEFAULT '' | | 29 | admin | localhost | NULL | Query | 0 | starting | show processlist | | 32 | admin | localhost | NULL | Sleep | 154 | | NULL | +----+-------+-----------+--------+---------+------+---------------------------------+------------------------------------+ 4 rows in set (0.00 sec)
PS:MDL元數(shù)據(jù)鎖的類型有很多種,根據(jù)官方手冊(cè)中對(duì)performance_schema.metadata_locks表的LOCK_TYPE字段的描述可得知,一共有9種(INTENTION_EXCLUSIVE、SHARED、SHARED_HIGH_PRIO、SHARED_READ、SHARED_WRITE、SHARED_UPGRADABLE、SHARED_NO_WRITE、SHARED_NO_READ_WRITE、EXCLUSIVE),但,官方手冊(cè)中并未找到每一種MDL鎖的具體含義和發(fā)生的場(chǎng)景,關(guān)于MDL鎖更詳細(xì)的信息可參考如下這兩個(gè)鏈接
https://blog.csdn.net/finalkof1983/article/details/88063328
| 作者簡(jiǎn)介
羅小波·沃趣科技高級(jí)數(shù)據(jù)庫(kù)技術(shù)專家
IT從業(yè)多年,主要負(fù)責(zé)MySQL 產(chǎn)品的數(shù)據(jù)庫(kù)支撐與售后二線支撐。曾參與版本發(fā)布系統(tǒng)、輕量級(jí)監(jiān)控系統(tǒng)、運(yùn)維管理平臺(tái)、數(shù)據(jù)庫(kù)管理平臺(tái)的設(shè)計(jì)與編寫,熟悉MySQL體系結(jié)構(gòu),Innodb存儲(chǔ)引擎,喜好專研開源技術(shù),多次在公開場(chǎng)合做過線下線上數(shù)據(jù)庫(kù)專題分享,發(fā)表過多篇數(shù)據(jù)庫(kù)相關(guān)的研究文章。
網(wǎng)頁(yè)名稱:MySQL執(zhí)行DDL語(yǔ)句hang住了怎么辦?-創(chuàng)新互聯(lián)
URL標(biāo)題:http://www.rwnh.cn/article32/ddcosc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、自適應(yīng)網(wǎng)站、網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、移動(dòng)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容