MySQL資料庫 DDL 阻塞問題定位 【轉載】

来源:https://www.cnblogs.com/xuliuzai/archive/2022/06/25/16411582.html
-Advertisement-
Play Games

1、簡述 binlog 二進位日誌文件,這個文件記錄了MySQL所有的DML操作。通過binlog日誌我們可以做數據恢復,增量備份,主主複製和主從複製等等。 2、Docker中無法使用vim問題解決 https://blog.csdn.net/Tomwildboar/article/details/ ...


轉載

【即拿即用:MySQL 中如何定位 DDL 被阻塞的問題?】

https://dbaplus.cn/news-11-4579-1.html

作者介紹

陳臣,甲骨文MySQL首席解決方案工程師,公眾號《MySQL實戰》作者,有大規模的MySQL,Redis,MongoDB,ES的管理和維護經驗,擅長MySQL資料庫的性能優化及日常操作的原理剖析。

1.引入

經常碰到開發、測試童鞋會問,線下開發、測試環境,執行了一個DDL,發現很久都沒有執行完,是不是被阻塞了?要怎麼解決?包括在群里,也經常會碰到類似問題:DDL 被阻塞了,如何找到阻塞它的 SQL ?

實際上,如何解決 DDL 被阻塞的問題,是 MySQL 中一個共性且高頻的問題。

下麵,就這個問題,給一個清晰明瞭、拿來即用的解決方案:

  • 怎麼判斷一個DDL是不是被阻塞了 ?

  • 當DDL被阻塞時,怎麼找出阻塞它的會話 ?

2.怎麼判斷一個 DDL是不是被阻塞了

首先,看一個簡單的Demo。

session1> create table sbtest.t1(id int primary key,name varchar(10));
Query OK, 0 rows affected (0.02 sec)
session1> insert into sbtest.t1 values(1,'a');
Query OK, 1 row affected (0.01 sec)
session1> begin;
Query OK, 0 rows affected (0.00 sec)
session1> select * from sbtest.t1;
+----+------+
| id | name |
+----+------+
|  1 | a    |
+----+------+
1 row in set (0.00 sec)
session2> alter table sbtest.t1 add c1 datetime;
阻塞中。。。
session3> show processlist;
+----+-----------------+-----------+------+---------+-------+---------------------------------+---------------------------------------+
| Id | User            | Host      | db   | Command | Time  | State                           | Info                                  |
+----+-----------------+-----------+------+---------+-------+---------------------------------+---------------------------------------+
|  5 | event_scheduler | localhost | NULL | Daemon  | 47628 | Waiting on empty queue          | NULL                                  |
| 24 | root            | localhost | NULL | Sleep   |    11 |                                 | NULL                                  |
| 25 | root            | localhost | NULL | Query   |     5 | Waiting for table metadata lock | alter table sbtest.t1 add c1 datetime |
| 26 | root            | localhost | NULL | Query   |     0 | init                            | show processlist                      |
+----+-----------------+-----------+------+---------+-------+---------------------------------+---------------------------------------+
4 rows in set (0.00 sec)

判斷一個 DDL 是不是被阻塞了,很簡單,就是執行 show processlist ,查看 DDL 操作對應的狀態。如果顯示的是 Waiting for table metadata lock ,則意味著這個 DDL 被阻塞了。DDL 一旦被阻塞了,後續針對該表的所有操作都會被阻塞,都會顯示 Waiting for table metadata lock 。這也是 DDL 讓人聞之色變的原因。碰到了類似場景,要麼 Kill DDL 操作,要麼 Kill 阻塞 DDL 的會話。Kill DDL 操作是一個治標不治本的方法,畢竟 DDL 操作總要執行。除此之外,對於 DDL 操作,需要獲取元資料庫鎖的階段有兩個:DDL 開始之初和 DDL 結束之前。如果是後者,就意味著之前的操作都要回滾,成本相對較高。所以,碰到類似場景,我們一般都會 Kill 阻塞 DDL 的會話。

那麼,怎麼知道是哪些會話阻塞了 DDL 呢?下麵我們看看具體的定位方法。

3.定位方法

3.1 方法一:sys.schema_table_lock_waits

sys.schema_table_lock_waits 是MySQL 5.7引入的,用來定位 DDL 被阻塞的問題。

針對上面這個Demo,我們看看sys.schema_table_lock_waits的輸出。

mysql> select * from sys.schema_table_lock_waits\G
*************************** 1. row ***************************
               object_schema: sbtest
                 object_name: t1
           waiting_thread_id: 62
                 waiting_pid: 25
             waiting_account: root@localhost
           waiting_lock_type: EXCLUSIVE
       waiting_lock_duration: TRANSACTION
               waiting_query: alter table sbtest.t1 add c1 datetime
          waiting_query_secs: 17
 waiting_query_rows_affected: 0
 waiting_query_rows_examined: 0
          blocking_thread_id: 61
                blocking_pid: 24
            blocking_account: root@localhost
          blocking_lock_type: SHARED_READ
      blocking_lock_duration: TRANSACTION
     sql_kill_blocking_query: KILL QUERY 24
sql_kill_blocking_connection: KILL 24
*************************** 2. row ***************************
               object_schema: sbtest
                 object_name: t1
           waiting_thread_id: 62
                 waiting_pid: 25
             waiting_account: root@localhost
           waiting_lock_type: EXCLUSIVE
       waiting_lock_duration: TRANSACTION
               waiting_query: alter table sbtest.t1 add c1 datetime
          waiting_query_secs: 17
 waiting_query_rows_affected: 0
 waiting_query_rows_examined: 0
          blocking_thread_id: 62
                blocking_pid: 25
            blocking_account: root@localhost
          blocking_lock_type: SHARED_UPGRADABLE
      blocking_lock_duration: TRANSACTION
     sql_kill_blocking_query: KILL QUERY 25
sql_kill_blocking_connection: KILL 25
2 rows in set (0.00 sec)

只有一個 alter 操作,卻產生了兩條記錄,而且兩條記錄的 Kill 對象還不一樣,其中一條 Kill 的對象還是 alter 操作本身。如果對錶結構不熟悉或不仔細看記錄內容的話,難免會 Kill 錯對象。不僅如此,在 DDL 操作被阻塞後,如果後續有 N 個查詢被 DDL 操作堵塞,還會產生 N*2 條記錄。在定位問題時,這 N*2 條記錄完全是個噪音。這個時候,就需要我們對上述記錄進行過濾了。過濾的關鍵是 blocking_lock_type 不等於 SHARED_UPGRADABLE。SHARED_UPGRADABLE 是一個可升級的共用元數據鎖,加鎖期間,允許併發查詢和更新,常用在 DDL 操作的第一階段。所以,阻塞DDL的不會是SHARED_UPGRADABLE。

故而,針對上面這個 case,我們可以通過下麵這個查詢來精確地定位出需要 Kill 的會話。

SELECT sql_kill_blocking_connection
FROM sys.schema_table_lock_waits
WHERE blocking_lock_type <> 'SHARED_UPGRADABLE'
 AND waiting_query = 'alter table sbtest.t1 add c1 datetime';

 3.2 方法二:Kill DDL 之前的會話

sys.schema_table_lock_waits 是 MySQL 5.7 才引入的。但在實際生產環境,MySQL 5.6還是占有相當多的份額。如何解決MySQL 5.6的這個痛點呢 ?細究下來,導致 DDL 被阻塞的操作,無非兩類:

  • 表上有慢查詢未結束。

  • 表上有事務未提交。

其中,第一類比較好定位,通過 show processlist 就能發現。而第二類僅憑 show processlist 很難定位,因為未提交事務的連接在 show processlist 中的狀態同空閑連接一樣,都是 Sleep 。所以,網上有 Kill 空閑連接的說法,其實也不無道理,但這樣做就太簡單粗暴了,難免會誤殺。其實,既然是事務,在 information_schema.innodb_trx中肯定會有記錄,如 session1 中的事務,在表中的記錄如下,

mysql> select * from information_schema.innodb_trx\G
*************************** 1. row ***************************
                    trx_id: 421568246406360
                 trx_state: RUNNING
               trx_started: 2022-01-02 08:53:50
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 0
       trx_mysql_thread_id: 24
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 0
     trx_lock_memory_bytes: 1128
           trx_rows_locked: 0
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
       trx_schedule_weight: NULL
1 row in set (0.00 sec)

其中 trx_mysql_thread_id 是線程 id ,結合 information_schema.processlist ,可進一步縮小範圍。所以,我們可以通過下麵這個 SQL ,定位出執行時間早於 DDL 的事務。

SELECT concat('kill ', i.trx_mysql_thread_id, ';')
FROM information_schema.innodb_trx i, (
    SELECT MAX(time) AS max_time
    FROM information_schema.processlist
    WHERE state = 'Waiting for table metadata lock'
      AND (info LIKE 'alter%'
      OR info LIKE 'create%'
      OR info LIKE 'drop%'
      OR info LIKE 'truncate%'
      OR info LIKE 'rename%'
  )) p
WHERE timestampdiff(second, i.trx_started, now()) > p.max_time;

可喜的是,當前正在執行的查詢也會顯示在information_schema.innodb_trx中。所以,上面這個 SQL 同樣也適用於慢查詢未結束的場景。

4.MySQL 5.7中使用sys.schema_table_lock_waits的註意事項

sys.schema_table_lock_waits 視圖依賴了一張 MDL 相關的表-performance_schema.metadata_locks。該表是 MySQL 5.7 引入的,會顯示 MDL 的相關信息,包括作用對象、鎖的類型及鎖的狀態等。但在 MySQL 5.7 中,該表預設為空,因為與之相關的 instrument 預設沒有開啟。MySQL 8.0 才預設開啟。

mysql> select * from performance_schema.setup_instruments where name='wait/lock/metadata/sql/mdl';
+----------------------------+---------+-------+
| NAME                       | ENABLED | TIMED |
+----------------------------+---------+-------+
| wait/lock/metadata/sql/mdl | NO      | NO    |
+----------------------------+---------+-------+
1 row in set (0.00 sec)

所以,在 MySQL 5.7 中,如果我們要使用 sys.schema_table_lock_waits ,必須首先開啟 MDL 相關的 instrument。開啟方式很簡單,直接修改 performance_schema.setup_instruments 表即可。

具體SQL如下:

UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME = 'wait/lock/metadata/sql/mdl';

但這種方式是臨時生效,實例重啟後,又會恢復為預設值。建議同步修改配置文件。

[mysqld]
performance-schema-instrument='wait/lock/metadata/sql/mdl=ON'

5.總結

1)執行 show processlist ,如果 DDL 的狀態是 Waiting for table metadata lock  ,則意味著這個 DDL 被阻塞了。

2)定位導致 DDL 被阻塞的會話,常用的方法有兩種:

  • sys.schema_table_lock_waits

SELECT sql_kill_blocking_connection
FROM sys.schema_table_lock_waits
WHERE blocking_lock_type <> 'SHARED_UPGRADABLE'
  AND (waiting_query LIKE 'alter%'
  OR waiting_query LIKE 'create%'
  OR waiting_query LIKE 'drop%'
  OR waiting_query LIKE 'truncate%'
  OR waiting_query LIKE 'rename%');

這種方法適用於 MySQL 5.7 和 8.0。

註意,MySQL 5.7 中,MDL 相關的 instrument 預設沒有打開。

  • Kill DDL 之前的會話
SELECT concat('kill ', i.trx_mysql_thread_id, ';')
FROM information_schema.innodb_trx i, (
    SELECT MAX(time) AS max_time
    FROM information_schema.processlist
    WHERE state = 'Waiting for table metadata lock'
      AND (info LIKE 'alter%'
      OR info LIKE 'create%'
      OR info LIKE 'drop%'
      OR info LIKE 'truncate%'
      OR info LIKE 'rename%'
  )) p
WHERE timestampdiff(second, i.trx_started, now()) > p.max_time;

如果 MySQL 5.7 中 MDL 相關的 instrument 沒有打開或在 MySQL 5.6 中,可使用該方法。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 表弟大學快畢業了,學了一個學期Python居然還不會寫學生管理系統,真的給我丟臉啊,教他又不肯學,還讓我直接給他寫,我真想兩巴掌上去,最終還是寫了給他,誰讓他是我表弟呢,關鍵時候還是得幫他一把! 寫完了放在那也是放著,所以今天分享給大家吧! 話不多說,咱們直接開始吧! 代碼解析 一、登錄頁面 1、定 ...
  • 領域邏輯 & 應用邏輯 如前所述,領域驅動設計中的業務邏輯分為兩部分(層):領域邏輯和應用邏輯: 領域邏輯由系統的核心領域規則組成,應用邏輯實現應用特定的用例 雖然定義很明確,但實現起來可能並不容易。您可能無法決定哪些代碼應該位於應用程式層,哪些代碼應該位於領域層。本節試圖解釋其中的差異 多個應用程 ...
  • 用例演示 - 創建實體 本節將演示一些示例用例並討論可選場景。 創建實體 從實體/聚合根類創建對象是實體生命周期的第一步。聚合/聚合根規則和最佳實踐部分 建議為Entity類創建一個主構造函數,以保證創建一個有效的實體。因此,無論何時我們需要創建實體的實例,我們都應該使用那個構造函數 參見下麵的問題 ...
  • 痞子衡嵌入式半月刊: 第 57 期 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回顧 ...
  • 2022年6月初合宙新上市了 Air32F103 系列 MCU, 分 Air32F103CBT6 和 Air32F103CCT6 兩個型號, 分別是 32K RAM + 128K FLASH 和 32K RAM + 256K FLASH, 支持的最高主頻216MHz, 可以Pin2Pin替換STM3... ...
  • ## 電腦性能設置 優化設置一:開啟卓越性能 其實,win10系統中有一個卓越性能的隱藏設置,它可以讓我們的電腦,在現有配置的情況下,發揮出最優良的性能。 1、 同時按住“win+R”打開運行視窗,輸入“powershell”並點擊“確定” 2、 打開命令提示符頁面後,輸入並執行以下字元,就會出現 ...
  • 寫在前面: 這幾天留校,在做一個電機驅動的項目,使用的是合肥傑發的平臺,車規級晶元AC7801/11系列晶元。 但在進行模擬和程式燒錄的時候遇到了各種問題,藉助這個機會,私下裡總結了常見的模擬與燒錄程式常見的幾種方式,以及相關的操作,希望對大家有幫助。 單片機ISP、IAP和ICP幾種燒錄方式的區別 ...
  • 對於 MySQL 資料庫作為各個業務系統的存儲介質,在系統中承擔著非常重要的職責,如果資料庫崩了,那麼對於讀和寫資料庫的操作都會受到影響。如果不能迅速恢復,對業務的影響是非常大的。本文我將分享MySQL 雙主 + Keepalived 的高可用落地和踩坑之路。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...