truncate比delete快是因为执行路径本质不同:truncate是ddl,直接释放数据段、重置fseg_header并截断.ibd文件;delete是dml,必须逐行加锁、写undo日志和binlog,遍历聚簇索引。

TRUNCATE 比 DELETE 快,根本不是“优化能解决”的问题,而是两条完全不同的执行路径——一个绕过 InnoDB 行级引擎,一个必须走完整 DML 流水线。
TRUNCATE 不扫描数据页,DELETE 必须遍历聚簇索引
TRUNCATE 是 DDL 操作,InnoDB 直接释放该表对应的数据段(segment),重置 FSEG_HEADER,把 .ibd 文件截断回初始大小(innodb_file_per_table=ON 时可见)。它不访问任何数据页,不扫描聚簇索引 B+ 树,也不读取一行数据。
DELETE 即使没写 WHERE,仍是标准 DML:InnoDB 启动事务、逐行遍历聚簇索引、对每行加 X 锁、打 delete bit、写 undo log、再按 binlog 格式序列化——百万行 = 百万次锁 + 日志 + 刷盘。
- 常见现象:
SHOW PROCESSLIST显示状态为Updating或Writing to net - 主从延迟飙升(尤其
binlog_format = ROW时,单条语句生成上万 event) -
innodb_log_file_size频繁刷盘,甚至触发innodb_force_recovery
TRUNCATE 不写 undo log,DELETE 必须为每一行生成日志
TRUNCATE 完全跳过 undo log 写入,所以不可回滚;redo log 只记页释放和元数据变更(如 segment 重置),不是逐行变更记录。binlog 仅写一条 TRUNCATE TABLE t DDL 事件。
DELETE 每删一行都生成 undo log 条目,用于 MVCC 和回滚;每行还生成 binlog row event;若表有二级索引,还要维护索引页的 delete bit —— 这些全是物理 I/O 开销。
- undo 表空间暴涨,可能占满磁盘
-
SELECT DATA_LENGTH, INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES查到的值在 DELETE 后不变,因为只是逻辑删除 - 想真正收缩空间,得
OPTIMIZE TABLE或ALTER TABLE ENGINE=InnoDB,但那是另一次全量重建
TRUNCATE 隐式提交且跳过触发器,DELETE 严格受事务和约束控制
TRUNCATE 在执行前自动提交当前事务(哪怕你刚写了 BEGIN),所以 BEGIN; TRUNCATE TABLE t; ROLLBACK; 中的 ROLLBACK 完全无效。它也不触发 BEFORE/AFTER DELETE 触发器,不检查外键约束(除非被其他表硬引用)。
DELETE 则全程运行在事务上下文中:触发器会执行、外键级联会生效、长事务会阻塞其他 DML、SQL_SAFE_UPDATES=1 下无 WHERE 会直接报错 ERROR 1175。
- 权限陷阱:
TRUNCATE需要DROP权限,不是DELETE权限 - 外键报错:
Cannot truncate a table referenced in a foreign key constraint→ 先SET FOREIGN_KEY_CHECKS = 0 - 自增重置:
TRUNCATE后AUTO_INCREMENT回到 1;DELETE不动计数器
TRUNCATE 是否真释放磁盘空间,取决于 innodb_file_per_table
这个配置决定你看到的“快”是不是真的省了磁盘:
- 为
ON(默认):TRUNCATE后ls -lh table_name.ibd立即变小,SELECT DATA_LENGTH数值归零 - 为
OFF:数据仍在共享表空间ibdata1中,TRUNCATE不释放操作系统可见空间;只能导出 +DROP+ 重建 + 导入
别只看文件大小变化,先查 SHOW VARIABLES LIKE 'innodb_file_per_table' —— 很多人卡在这一步,以为 TRUNCATE 失效,其实是配置没生效。











