truncate table虽快但可能卡住,因其需等待mdl锁、清空buffer pool、重置auto_increment;若表被长事务读写,会阻塞在“waiting for table metadata lock”,影响所有查询;安全替代方案是rename + drop,将耗时操作异步化,业务无感。

别用 DELETE FROM table,也别直接 TRUNCATE TABLE —— 除非你确认表没被任何应用实时读写、没外键依赖、且能接受几秒到几分钟的元数据锁阻塞。
为什么 TRUNCATE 在大表上也可能卡住
TRUNCATE TABLE 虽然比 DELETE 快,但它仍是 DDL 操作,在 InnoDB 中会触发以下动作:等待所有活跃事务释放该表的 MDL(元数据锁)、清空 buffer pool 中相关页、重置 auto_increment、并最终标记 .ibd 文件为可回收。如果此时有长事务正在查这张表,TRUNCATE 就会卡在“waiting for table metadata lock”状态,业务查询全挂。
- 常见现象:
SHOW PROCESSLIST看到Truncate table状态长时间为Waiting for table metadata lock - 影响范围:不只是写,任何未提交的
SELECT(哪怕只是SELECT ... FOR UPDATE或隐式开启事务)都会阻塞它 - 分区表例外:若表按时间分区,可直接
ALTER TABLE t DROP PARTITION p202401,毫秒级,不锁表
真正安全的清空路径:RENAME + DROP
核心是把“删数据”变成“换名字”,把耗时操作挪到后台异步执行,业务几乎无感。
- 第一步(秒级):
RENAME TABLE big_log TO big_log_to_drop—— 原表瞬间不可见,新表名立即可用 - 第二步(可选):建同结构空表
CREATE TABLE big_log LIKE big_log_to_drop,或直接让应用重建 - 第三步(后台):
DROP TABLE big_log_to_drop—— 此时才真正清理数据,IO 压力由后台 purge 线程慢慢消化 - 关键点:rename 后立刻检查应用日志,确认无 “Table doesn’t exist” 报错;若发现,说明有硬编码表名,需改代码或加兼容视图
删完之后磁盘空间还不释放?这是正常现象
InnoDB 的 .ibd 文件不会因 DROP 自动缩小,空间只是标记为“可复用”。即使你刚删掉 50GB 数据,du -sh 看文件大小不变。
- 验证是否真释放:
SELECT FILE_NAME, TABLE_NAME, ALLOCATED_SIZE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES(MySQL 8.0+),看ALLOCATED_SIZE是否下降 - 想物理收缩?只能导出再导入:
mysqldump --no-create-info big_db big_table | mysql big_db,但千万级表 dump/load 成本极高,慎用 - 更现实的做法:监控
innodb_data_free(通过SHOW ENGINE INNODB STATUS),只要它持续增长,说明空间已在内部复用
最易被忽略的一点:rename 前必须确认表没被任何存储过程、事件、触发器或定时任务引用——这些对象不会随 rename 自动更新,会静默失败或报错,而错误日志可能被淹没在大量慢查询里。











