TRUNCATE比DELETE快的根本原因是其为DDL操作,直接释放数据页或段,不逐行扫描、不记录单行日志、不触发触发器;而DELETE是DML,需逐行处理日志、索引、约束等冗余开销。
TRUNCATE 比 DELETE 快的根本原因
TRUNCATE 是 DDL 操作,直接释放数据页(page)或段(segment),不逐行扫描、不记录单行 DELETE 日志,也不触发触发器。而 DELETE 是 DML,会为每一行生成日志、维护索引、检查外键约束、可能触发 ON DELETE 行为——这些在清空整表时全是冗余开销。
-
TRUNCATE通常只写一条事务日志(如 SQL Server 的LOP_TRUNCATE_PAGE,PostgreSQL 的RELATION TRUNCATE) - 不锁全表?错:多数数据库仍需获取排他锁(
X lock),但持有时间极短 - 不走事务日志重做?不完全对:它仍记日志,只是粒度粗、量极少;InnoDB 中
TRUNCATE本质是DROP + CREATE,会重建聚簇索引
哪些情况不能用 TRUNCATE 替代 DELETE
TRUNCATE 看似万能,但实际限制比想象中多:
- 表被其他表通过外键(
FOREIGN KEY)引用(MySQL 8.0+ 支持级联截断,但需显式声明ON DELETE CASCADE,且TRUNCATE本身不触发该行为) - 当前会话正持有该表的未提交事务(如已
SELECT ... FOR UPDATE) - 使用了复制(replication)且 binlog 格式为
STATEMENT:MySQL 中TRUNCATE在该模式下不可见于从库(5.7+ 默认改用MIXED或ROW后才安全) - 需要条件清空(比如只删
status = 'archived'的行)→ 只能用DELETE或分区表DROP PARTITION - 表上有启用的触发器(
TRUNCATE绝对不触发任何BEFORE/AFTER DELETE)
不同数据库中 TRUNCATE 的关键行为差异
行为不一致是线上翻车高发区,尤其跨数据库迁移时: