溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL 5.6中怎么定位DDL被阻塞的問題

發(fā)布時間:2021-10-29 16:51:05 來源:億速云 閱讀:168 作者:小新 欄目:MySQL數(shù)據(jù)庫

這篇文章將為大家詳細(xì)講解有關(guān)MySQL 5.6中怎么定位DDL被阻塞的問題,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

對于DDL被阻塞問題的定位,我們主要是基于MySQL 5.7新引入的performance_schema.metadata_locks表。提出的定位方法,頗有種"錦上添花"的意味,而且,也只適用于MySQL 5.7開始的版本。

但在實際生產(chǎn)中,MySQL 5.6還是占絕不多數(shù)。雖然MySQL 8.0都已經(jīng)GA了,但鑒于數(shù)據(jù)庫的特殊性,在對待升級的這個事情上,相當(dāng)一部分人還是秉持著一種“不主動”的態(tài)度。

既然MySQL 5.6用者眾多,有沒有一種方法,來解決MySQL 5.6的這個痛點呢?

還是之前的測試Demo。

會話1開啟了事務(wù)并執(zhí)行了三個操作,但未提交,此時,會話2執(zhí)行了alter table操作,被阻塞。

  1. session1> begin;

  2. Query OK, rows affected (0.00 sec)



  3. session1> delete from slowtech.t1 where id=2;

  4. Query OK, 1 row affected (0.00 sec)



  5. session1> select * from slowtech.t1;

  6. +------+------+

  7. | id   | name |

  8. +------+------+

  9. |    1 | a    |

  10. +------+------+

  11. 1 row in set (0.00 sec)



  12. session1> update slowtech.t1 set name='c' where id=1;

  13. Query OK, 1 row affected (0.00 sec)

  14. Rows matched: 1  Changed: 1  Warnings:



  15. session2> alter table slowtech.t1 add c1 int; ##被阻塞



  16. session3> show processlist;

  17. +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+

  18. | Id | User | Host      | db   | Command | Time | State                           | Info                               |

  19. +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+

  20. |  2 | root | localhost | NULL | Sleep   |   51 |                                 | NULL                               |

  21. |  3 | root | localhost | NULL | Query   |     | starting                        | show processlist                   |

  22. |  4 | root | localhost | NULL | Query   |    9 | Waiting for table metadata lock | alter table slowtech.t1 add c1 int |

  23. +----+------+-----------+------+---------+------+---------------------------------+------------------------------------+

  24. 3 rows in set (0.00 sec)

                提示,類似代碼可左右滑動

其實,導(dǎo)致DDL阻塞的操作,無非兩類: 

1. 慢查詢  

2. 表上有事務(wù)未提交

其中,第一類比較好定位,通過show processlist即能發(fā)現(xiàn)。而第二類基本沒法定位,因為未提交事務(wù)的連接在show processlist中的輸出同空閑連接一樣。

如下面Id為2的連接,雖然Command顯示為“Sleep”,其實是事務(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)連接的說法,其實也不無道理,但這樣做就太簡單粗暴了,難免會誤殺。

其實,既然是事務(wù),在information_schema. innodb_trx中肯定會有記錄,如會話1中的事務(wù),在表中的記錄如下,

mysql> select * from information_schema.innodb_trx\G*************************** 1. row ***************************                    trx_id: 1050390                 trx_state: RUNNING               trx_started: 2018-07-17 08:55:32     trx_requested_lock_id: NULL          trx_wait_started: NULL                trx_weight: 4       trx_mysql_thread_id: 2                 trx_query: NULL       trx_operation_state: NULL         trx_tables_in_use: 0         trx_tables_locked: 1          trx_lock_structs: 2     trx_lock_memory_bytes: 1136           trx_rows_locked: 3         trx_rows_modified: 2   trx_concurrency_tickets: 0       trx_isolation_level: REPEATABLE READ         trx_unique_checks: 1    trx_foreign_key_checks: 1trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0          trx_is_read_only: 0trx_autocommit_non_locking: 01 row in set (0.00 sec)

其中trx_mysql_thread_id是線程id,結(jié)合performance_schema.threads,可以知道當(dāng)前哪些連接上存在著活躍事務(wù),這樣就進(jìn)一步縮小了可被kill的線程范圍。

但從影響程度上,和kill所有Command為Sleep的連接沒太大區(qū)別,畢竟,kill真正的空閑連接對業(yè)務(wù)的影響不大。

有沒有辦法能更精確地定位出阻塞會話呢?

有,答案還是在于之前介紹的performance_ schema.events_statements_history表。

在上篇MySQL 5.7的分析中,我們是首先知道引發(fā)阻塞的線程ID,然后利用events_statements_history表,查看該線程的相關(guān)SQL。

而在MySQL 5.6中,我們并不知道引發(fā)阻塞的線程ID,但是,我們可以反其道而行之,利用窮舉法,首先統(tǒng)計出所有線程在當(dāng)前事務(wù)執(zhí)行過的所有SQL,然后再判斷這些SQL中是否包含目標(biāo)表。

具體SQL如下,

SELECT    processlist_id,    sql_text FROM    (    SELECT        c.processlist_id,        substring_index( sql_text, "transaction_begin;",-1 ) sql_text     FROM        information_schema.innodb_trx a,        (        SELECT            thread_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         FROM            performance_schema.events_statements_history         GROUP BY            thread_id         ) b,        performance_schema.threads c     WHERE        a.trx_mysql_thread_id = c.processlist_id         AND b.thread_id = c.thread_id     ) t WHERE    sql_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)

從輸出來看,確實也達(dá)到了預(yù)期效果。

需要注意的是,在MySQL5.6中,events_ statements_history默認(rèn)是沒有開啟的。

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)

關(guān)于“MySQL 5.6中怎么定位DDL被阻塞的問題”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI