delete比truncate慢,因其逐行执行dml全流程:加x锁、写undo/redo、标记删除位、维护索引,不释放空间;truncate是原子性ddl操作,直接重置段和文件,仅写元数据日志,毫秒级完成。

DELETE 比 TRUNCATE 慢,不是因为“没优化好”,而是两者根本不在同一条执行路径上——一个在行级引擎里走完整事务流水线,另一个直接绕过引擎、重置物理结构。
DELETE 必须逐行走完 InnoDB 全流程
DELETE FROM t(哪怕没 WHERE)仍是标准 DML:
- 启动事务,为每一行加 X 锁,持有时间随数据量线性增长
- 对每行打
delete bit,不释放数据页,只是逻辑标记 - 每行写一条
undo log(用于 MVCC 和回滚),100 万行 = 100 万条 undo 记录 - 每行再按
binlog_format序列化成 event(ROW模式下体积爆炸) - 若有二级索引,还要同步更新索引页上的 delete bit
- 最终
DATA_LENGTH不变,磁盘空间不释放,OPTIMIZE TABLE才能收缩
常见卡点:
-
SHOW PROCESSLIST显示Updating或Writing to net -
innodb_log_file_size频繁刷盘,甚至触发innodb_force_recovery - 主从延迟飙升,尤其
binlog_format = ROW时
TRUNCATE 是原子性段级操作,不碰数据页
TRUNCATE TABLE t 在 InnoDB 中等价于“释放 segment + 截断 .ibd 文件 + 重置 FSEG_HEADER”:
- 不扫描聚簇索引,不读取任何数据页
- 不写行级
undo log,只记元数据变更(如 segment 重置)到 redo -
binlog只写一条TRUNCATE TABLE tDDL 事件 -
innodb_file_per_table = ON时,.ibd文件瞬间缩回初始大小 -
AUTO_INCREMENT计数器重置为 1(InnoDB 行为)
限制即代价:
- 需要
DROP权限,不是DELETE权限 - 报错
Cannot truncate a table referenced in a foreign key constraint→ 先SET FOREIGN_KEY_CHECKS = 0 - 无法回滚:
BEGIN; TRUNCATE TABLE t; ROLLBACK;中的ROLLBACK无效
别被“锁粒度”误导:TRUNCATE 也要表锁,但极短
很多人以为 TRUNCATE “不锁表”,其实它仍需获取排他锁(X lock),只是整个操作毫秒级完成,锁持有时间几乎不可测;而 DELETE 的锁是逐行加、逐行释放,总持有时间与数据量正相关。线上大表清空,锁争用和长事务阻塞才是第一杀手。
真正容易被忽略的点是:TRUNCATE 成功的前提不是“语法对”,而是外键、权限、活跃事务、复制模式这四层环境全部就绪——少检查一项,就会在凌晨三点收到告警。











