truncate 几乎总是比 delete 快,因它直接释放数据页、重置自增计数器且日志记录极少;但受限于外键约束、不可回滚、不触发触发器,且在sbr复制下可能不安全。

TRUNCATE 和 DELETE 哪个更快?
TRUNCATE 几乎总是比 DELETE 快,尤其对大表。它不逐行删除,而是直接释放数据页、重置自增计数器,并跳过事务日志的完整记录(在 InnoDB 中仍会写入少量日志,但远少于 DELETE)。如果你的目标是「彻底清空且不关心回滚、触发器、逐行逻辑」,TRUNCATE TABLE 是首选。
为什么 TRUNCATE 有时执行失败?
常见报错如 ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint,说明该表被其他表的外键引用。InnoDB 默认禁止 TRUNCATE 这类表,因为它是 DDL 操作,无法被外键约束的级联机制捕获。
- 临时方案:先禁用外键检查
SET FOREIGN_KEY_CHECKS = 0;,再执行TRUNCATE TABLE t1;,最后恢复SET FOREIGN_KEY_CHECKS = 1; - 更安全的做法:改用
DELETE FROM t1;(不带 WHERE),它受外键约束约束,会触发级联或拒绝操作,行为可预测 - 注意:
TRUNCATE不能加 WHERE 条件,也不能在事务中依赖其回滚语义——它在多数存储引擎中隐式提交
DELETE FROM t1 和 DELETE FROM t1 WHERE 1 的性能差异
两者实际执行效果一样,都是全表删除,但写法暴露了常见误区。MySQL 优化器会忽略 WHERE 1,仍走全表扫描 + 逐行标记删除。真正影响性能的是:
- 是否带 WHERE 条件:有则走索引(若可用),无则全扫
- 是否启用 autocommit:关闭时,大表
DELETE可能撑爆 undo log,甚至导致事务超时 - 是否有触发器:
DELETE会触发BEFORE/AFTER DELETE,TRUNCATE完全不触发 - 自增 ID 是否重置:
DELETE不重置,TRUNCATE重置为 1(除非使用ALTER TABLE ... AUTO_INCREMENT = N手动指定)
线上环境清空表前必须确认的三件事
别只看语句快不快,得看上下文是否允许。
- 确认表是否被复制(replication):TRUNCATE 在基于语句的复制(SBR)下可能不安全,建议使用 ROW 格式,或统一用 DELETE 避免主从不一致
- 确认是否有活跃连接正在读该表:TRUNCATE 是 DDL,会获取元数据锁(MDL),阻塞后续 SELECT,直到完成;而 DELETE 在大表上可能锁行更久,但不会阻塞新查询发起(只是慢)
- 确认备份与监控是否就绪:TRUNCATE 后 binlog 里只有一条语句,闪回困难;DELETE 虽慢,但每行删除都记日志,理论上支持按时间点或条件恢复
真正难的不是选命令,而是判断“此刻能不能承受 TRUNCATE 带来的不可逆性”。比如清空日志表可以大胆 TRUNCATE,清空用户订单中间表就得先查外键、看复制模式、翻监控看当前 QPS。











