Metadata Lock (MDL) 是 MySQL 5.5+ 引入的**元數據鎖機制**,核心目的是**保護資料庫對象定義(表結構、視圖、函數等)在 DDL 與 DML/查詢並發時的一致性**。本文補充前兩篇未覆蓋的鎖類型細分、對象維度劃分,並解釋查詢阻塞成因與 mysqldump 一致性備份原理。
| 鎖類型 | 標識符 | 兼容性 | 典型獲取場景 |
|---|---|---|---|
| 意圖共享鎖 | MDL_INTENTION_SHARED | 兼容所有共享類鎖 | SELECT、INSERT、UPDATE、DELETE 等 DML 操作前置 |
| 共享鎖 | MDL_SHARED | 兼容 IS、S;阻塞 X | LOCK TABLES ... READ、FLUSH TABLES WITH READ LOCK |
| 高優先級共享鎖 | MDL_SHARED_HIGH_PRIO | 兼容 IS、S;阻塞 X,優先於 SH | SELECT ... LOCK IN SHARE MODE、外鍵檢查 |
| 共享寫鎖 | MDL_SHARED_WRITE | 兼容 IS;阻塞 S、SH、SW、X | LOCK TABLES ... WRITE (舊版) |
| 排他鎖 | MDL_EXCLUSIVE | **阻塞所有其他鎖** | DDL (ALTER、DROP、TRUNCATE)、FLUSH TABLES WITH READ LOCK 後續 |
| 排他鎖 (無鎖等待) | MDL_EXCLUSIVE_NO_WAIT | 不等待,衝突即失敗 | RENAME TABLE、DROP DATABASE 等元數據操作 |
| 對象類型 | 鎖定粒度 | 典型場景 |
|---|---|---|
| GLOBAL | 整個實例 | FLUSH TABLES WITH READ LOCK、SET GLOBAL read_only=ON |
| SCHEMA | 庫級 | CREATE/DROP DATABASE、RENAME DATABASE (5.7 移除) |
| TABLE | 表級 (最常見) | 所有 DML/DDL、LOCK TABLES |
| FUNCTION/PROCEDURE | 程式對象級 | CREATE/DROP FUNCTION、CALL |
| TRIGGER | 觸發器級 | CREATE/DROP TRIGGER |
| EVENT | 事件調度器級 | CREATE/DROP EVENT |
| TABLESPACE | 表空間級 | ALTER TABLESPACE、DROP TABLESPACE |
| LOCKING SERVICE | 命名鎖服務 | GET_LOCK()、RELEASE_LOCK() |
-- 會話 A:長時間運行的事務 (未提交)
BEGIN;
SELECT * FROM t WHERE id = 1 FOR UPDATE; -- 持有表 MDL_SHARED (隱式)
-- 停留 10 分鐘...
-- 會話 B:DDL 操作
ALTER TABLE t ADD COLUMN c INT; -- 申請 MDL_EXCLUSIVE,被 A 阻塞,進入 Waiting for table metadata lock
-- 會話 C:普通查詢 (自動提交)
SELECT * FROM t; -- 申請 MDL_SHARED,被 B 的 EXCLUSIVE 等待阻塞!
-- 會話 D...N:所有後續訪問 t 的查詢全部堆積
根因: MDL 兼容性矩陣中,**EXCLUSIVE 與所有鎖互斥**。DDL 等待 MDL_EXCLUSIVE 時,已在隊列中佔位,**後續所有申請 SHARED/IS 的查詢均在 DDL 之後排隊**,形成「DDL 阻塞查詢」的連鎖效應。
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_NAME='t'\G 定位持有者KILL 長事務會話 (慎用,業務影響)pt-online-schema-change / gh-ost 繞過 MDL_EXCLUSIVElock_wait_timeout 避免無限等待metadata_locks 表,告警長時間等待mysqldump --single-transaction --master-data=2 db_name > dump.sql
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READFLUSH TABLES WITH READ LOCK → 獲取 GLOBAL MDL_SHARED → 記錄 Binlog 位點 → **立即釋放**FLUSH TABLES WITH READ LOCK 持有 **GLOBAL MDL_SHARED** 整個備份過程| 模式 | MDL 鎖持有 | 阻塞寫入 | 適用引擎 | 一致性 |
|---|---|---|---|---|
--single-transaction | GLOBAL 瞬間 + 表級無 (InnoDB) | 毫秒級 | InnoDB 為主 | 強一致 (快照) |
| 預設 (無參數) | GLOBAL 全程 | 全程阻塞 | 所有 | 強一致 (鎖) |
--lock-all-tables | 所有表 S 鎖 | 全程阻塞 | MyISAM/混合 | 強一致 |
最佳實踐: 生產備份**強制使用 --single-transaction --master-data=2**,確保 InnoDB 表零阻塞、基於位點增量恢復。MyISAM 表建議遷移至 InnoDB 或接受短暫鎖表。