執行 DROP TABLE large_table (10GB+) 時,整個 MySQL 實例所有查詢阻塞 7 秒+,SHOW PROCESSLIST 顯示其他查詢卡在 Opening tables 狀態。本文揭示核心原因:LOCK_open 全局互斥鎖保護整個刪除過程,ext3 文件系統刪除大文件極慢導致鎖持有時間過長,並提供文件系統升級、變通操作、內核優化建議。
mysql> DROP TABLE large_table;
Query OK, 0 rows affected (7.44 sec) -- 7 秒內全庫寫/讀阻塞
-- 並發查詢狀態
+----+------+-----------+------+---------+------+----------------+----------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+------+---------+------+----------------+----------------------------------+
| 1 | root | localhost | test | Query | 7 | NULL | drop table large_table |
| 329| root | localhost | test | Query | 7 | Opening tables | select * from other_table limit 1 |
+----+------+-----------+------+---------+------+----------------+----------------------------------+
MySQL 源碼 sql/sql_table.cc 中 mysql_rm_table() 流程:
VOID(pthread_mutex_lock(&LOCK_open));
error = mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0);
pthread_mutex_unlock(&LOCK_open);
整個刪除過程(加鎖表、存儲引擎刪文件、刪 .frm、清理字典緩存)均在 LOCK_open 保護下串行執行。
LOCK_open 是 MySQL 表緩存系統的核心鎖,任何打開/關閉表、創建/刪除表、FLUSH TABLES、SHOW TABLE STATUS 等操作都需獲取此鎖。鎖持有期間,所有線程嘗試訪問表緩存均阻塞於 Opening tables 狀態。
LOCK_open 持續持有。-- ext3
mysql> DROP TABLE large_table;
Query OK, 0 rows affected (7.44 sec)
-- XFS (同樣數據文件)
mysql> DROP TABLE large_table;
Query OK, 0 rows affected (0.29 sec) -- 25 倍快!
XFS 使用 extent 映射、延遲分配、並行元數據操作,大文件刪除極快。
| 嘗試方案 | 結果 | 原因 |
|---|---|---|
TRUNCATE TABLE + DROP TABLE | 同樣慢 | TRUNCATE 內部同樣獲取 LOCK_open 刪文件 |
ALTER TABLE ... ENGINE=MyISAM + DROP | 同樣慢 | ALTER TABLE 重建表過程需 LOCK_open 刪舊文件 |
OPTIMIZE TABLE + DROP | 同樣慢 | 同理,重建表刪文件持有 LOCK_open |
所有 DDL 刪除文件操作均受 LOCK_open 保護,無法繞過。
ALTER TABLE logs DROP PARTITION p_202301;
DROP PARTITION 同樣需 LOCK_open,但單個分區文件小,刪除快,鎖持有時間可控。配合 EXCHANGE PARTITION 實現無鎖歸檔。RENAME TABLE large_table TO large_table_to_drop; (極快,僅修改字典) → 後台異步線程刪除物理文件 (無 LOCK_open)。LOCK_open 內同步刪除。社區有 Patch 提議「懶惰刪除」,未合入主線。innodb_file_per_table=ON 時,DROP TABLE 刪除 .ibd 文件同樣持有 LOCK_open,大表同樣阻塞。LOCK_open 等待:SHOW STATUS LIKE 'Table_open_cache%';、performance_schema.events_waits_summary_global_by_event_name 關注 wait/synch/mutex/sql/LOCK_open。參考 MythTV 方案:後台線程分塊 truncate/fallocate(FALLOC_FL_PUNCH_HOLE) 釋放文件空間,避免單次大文件刪除阻塞。需應用層實現:
# 概念腳本
RENAME TABLE big TO big_deleting;
# 後台循環
while [ $(stat -c%s big_deleting.ibd) -gt 0 ]; do
fallocate -p -o $offset -l $chunk big_deleting.ibd
sleep 0.1
done
rm big_deleting.ibd
DROP TABLE 極慢本質是 LOCK_open 全局互斥鎖 + 文件系統大文件刪除慢 的雙重疊加。根治路徑:**文件系統升級至 XFS/ext4** 為最直接有效;架構層面採用 **分區表 + DROP PARTITION** 將大文件拆小;運維層面 **嚴禁高峰期大表 DDL、建立異步歸檔刪除流程**。期待 MySQL 內核引入「懶惰刪除」或「後台異步文件清理」機制徹底解決此歷史包袱。