MySQL 5.6中如何定位DDL被阻塞的问题
在上一篇文章《MySQL 5.7中如何定位DDL被阻塞的問(wèn)題》中,對(duì)于DDL被阻塞問(wèn)題的定位,我們主要是基于MySQL 5.7新引入的performance_schema.metadata_locks表。提出的定位方法,頗有種"錦上添花"的意味,而且,也只適用于MySQL 5.7開(kāi)始的版本。
但在實(shí)際生產(chǎn)中,MySQL 5.6還是占絕不多數(shù)。雖然MySQL 8.0都已經(jīng)GA了,但鑒于數(shù)據(jù)庫(kù)的特殊性,在對(duì)待升級(jí)的這個(gè)事情上,相當(dāng)一部分人還是秉持著一種“不主動(dòng)”的態(tài)度。
既然MySQL 5.6用者眾多,有沒(méi)有一種方法,來(lái)解決MySQL 5.6的這個(gè)痛點(diǎn)呢?
?
還是之前的測(cè)試Demo
會(huì)話(huà)1開(kāi)啟了事務(wù)并執(zhí)行了三個(gè)操作,但未提交,此時(shí),會(huì)話(huà)2執(zhí)行了alter table操作,被阻塞。
session1> begin; Query OK, 0 rows affected (0.00 sec)session1> delete from slowtech.t1 where id=2; Query OK, 1 row affected (0.00 sec)session1> select * from slowtech.t1; +------+------+ | id | name | +------+------+ | 1 | a | +------+------+ row in set (0.00 sec)session1> update slowtech.t1 set name='c' where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0session2> alter table slowtech.t1 add c1 int; ##被阻塞session3> show processlist; +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+ | 2 | root | localhost | NULL | Sleep | 51 | | NULL | | 3 | root | localhost | NULL | Query | 0 | starting | show processlist | | 4 | root | localhost | NULL | Query | 9 | Waiting for table metadata lock | alter table slowtech.t1 add c1 int | +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+ rows in set (0.00 sec)
?
其實(shí),導(dǎo)致DDL阻塞的操作,無(wú)非兩類(lèi):?
1. 慢查詢(xún)??
2. 表上有事務(wù)未提交
其中,第一類(lèi)比較好定位,通過(guò)show processlist即能發(fā)現(xiàn)。而第二類(lèi)基本沒(méi)法定位,因?yàn)槲刺峤皇聞?wù)的連接在show processlist中的輸出同空閑連接一樣。
如下面Id為2的連接,雖然Command顯示為“Sleep”,其實(shí)是事務(wù)未提交。
mysql> show processlist; +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+ | 2 | root | localhost | NULL | Sleep | 77 | | NULL | | 3 | root | localhost | NULL | Query | 0 | starting | show processlist | | 4 | root | localhost | NULL | Query | 44 | Waiting for table metadata lock | alter table slowtech.t1 add c1 int | +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+ 3 rows in set (0.00 sec)
?
所以,網(wǎng)上有kill空閑(Command為Sleep)連接的說(shuō)法,其實(shí)也不無(wú)道理,但這樣做就太簡(jiǎn)單粗暴了,難免會(huì)誤殺。
其實(shí),既然是事務(wù),在information_schema. innodb_trx中肯定會(huì)有記錄,如會(huì)話(huà)1中的事務(wù),在表中的記錄如下,
mysql> select * from information_schema.innodb_trx\G *************************** 1. row ***************************trx_id: 1050390trx_state: RUNNINGtrx_started: 2018-07-17 08:55:32trx_requested_lock_id: NULLtrx_wait_started: NULLtrx_weight: 4trx_mysql_thread_id: 2trx_query: NULLtrx_operation_state: NULLtrx_tables_in_use: 0trx_tables_locked: 1trx_lock_structs: 2trx_lock_memory_bytes: 1136trx_rows_locked: 3trx_rows_modified: 2trx_concurrency_tickets: 0trx_isolation_level: REPEATABLE READtrx_unique_checks: 1trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULLtrx_adaptive_hash_latched: 0trx_adaptive_hash_timeout: 0trx_is_read_only: 0 trx_autocommit_non_locking: 0 1 row in set (0.00 sec)
?
其中trx_mysql_thread_id是線(xiàn)程id,結(jié)合performance_schema.threads,可以知道當(dāng)前哪些連接上存在著活躍事務(wù),這樣就進(jìn)一步縮小了可被kill的線(xiàn)程范圍。
?但從影響程度上,和kill所有Command為Sleep的連接沒(méi)太大區(qū)別,畢竟,kill真正的空閑連接對(duì)業(yè)務(wù)的影響不大。
?此時(shí),依然可以借助performance_schema. events_statements_history表。
?在上篇MySQL 5.7的分析中,我們是首先知道引發(fā)阻塞的線(xiàn)程ID,然后利用events_statements_history表,查看該線(xiàn)程的相關(guān)SQL。
?而在MySQL 5.6中,我們并不知道引發(fā)阻塞的線(xiàn)程ID,但是,我們可以反其道而行之,利用窮舉法,首先統(tǒng)計(jì)出所有線(xiàn)程在當(dāng)前事務(wù)執(zhí)行過(guò)的所有SQL,然后再判斷這些SQL中是否包含目標(biāo)表。
?
具體SQL如下,
SELECTprocesslist_id,sql_text FROM(SELECTc.processlist_id,substring_index( sql_text, "transaction_begin;",-1 ) sql_text FROMinformation_schema.innodb_trx a,(SELECTthread_id,group_concat( CASE WHEN EVENT_NAME = 'statement/sql/begin' THEN "transaction_begin" ELSE sql_text END ORDER BY event_id SEPARATOR ";" ) AS sql_text FROMperformance_schema.events_statements_history GROUP BYthread_id ) b,performance_schema.threads c WHEREa.trx_mysql_thread_id = c.processlist_id AND b.thread_id = c.thread_id ) t WHEREsql_text LIKE '%t1%';+----------------+---------------------------------------------------------------------------------------------------------+ | processlist_id | sql_text | +----------------+---------------------------------------------------------------------------------------------------------+ | 2 | delete from slowtech.t1 where id=2;select * from slowtech.t1;update slowtech.t1 set name='c' where id=1 | +----------------+---------------------------------------------------------------------------------------------------------+ 1 row in set (0.01 sec)
從輸出來(lái)看,確實(shí)也達(dá)到了預(yù)期效果。
?
需要注意的是,在MySQL5.6中,events_statements_history默認(rèn)是沒(méi)有開(kāi)啟的。
mysql> SELECT * FROM performance_schema.setup_consumers WHERE NAME LIKE '%statements%'; +--------------------------------+---------+ | NAME | ENABLED | +--------------------------------+---------+ | events_statements_current | YES | | events_statements_history | NO | | events_statements_history_long | NO | | statements_digest | YES | +--------------------------------+---------+ 4 rows in set (0.00 sec)
?
轉(zhuǎn)載于:https://www.cnblogs.com/ivictor/p/9460192.html
總結(jié)
以上是生活随笔為你收集整理的MySQL 5.6中如何定位DDL被阻塞的问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: “如此十馀年”下一句是什么
- 下一篇: 安装Nginx