truncate是ddl操作,delete是dml操作,二者底层执行路径完全不同:truncate直接释放数据段、重置自增、不写undo log且隐式提交;delete逐行加锁、打删除标记、写undo和binlog,支持事务回滚但性能差。

TRUNCATE 是 DDL,DELETE 是 DML,根本不在同一条执行路径上
这不是“优化一下就能快”的问题,而是 MySQL 底层引擎压根不走同一套流程。TRUNCATE TABLE 被 InnoDB 当作元数据操作处理:直接释放整个数据段、重置 FSEG_HEADER、截断 .ibd 文件;而 DELETE FROM t 即使没 WHERE,也必须启动事务、逐行扫描聚簇索引、对每行加 X 锁、打 delete bit、写 undo log 和 binlog event。
常见现象包括:SHOW PROCESSLIST 显示状态长期卡在 Updating;主从延迟飙升(尤其 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 TABLE 只需极短时间持有表级排他锁(X lock),清空完立刻释放;而 DELETE FROM t 在整批删除过程中持续持有行锁或间隙锁,锁持有时间与数据量正相关。千万级表上,DELETE 可能锁表几十秒甚至分钟,TRUNCATE 在毫秒级完成。
执行 DELETE FROM t 时,SHOW ENGINE INNODB STATUS 常看到大量 LOCK_WAIT 或 RECORD LOCKS;执行 TRUNCATE TABLE t 时,INFORMATION_SCHEMA.INNODB_TRX 几乎查不到对应事务记录。
-
TRUNCATE隐式提交,不参与事务上下文管理,BEGIN; TRUNCATE TABLE t; ROLLBACK;中的ROLLBACK对它完全无效 -
TRUNCATE不触发BEFORE/AFTER DELETE触发器,也不检查外键约束(除非被其他表硬引用) - 权限陷阱:
TRUNCATE需要DROP权限,不是DELETE权限
TRUNCATE 会重置 AUTO_INCREMENT,DELETE 不会
TRUNCATE 执行后,自增计数器回到初始值(通常是 1);DELETE 即使删光所有行,自增值仍保持在最后插入的 ID 上。
这看似是小差异,但影响真实业务逻辑:比如你依赖自增 ID 做幂等判断、分库分表路由或导出序号连续性,用错命令会导致下游解析异常。
真正容易被忽略的是:TRUNCATE 的“快”,建立在它完全绕过事务锁管理机制之上——不是它锁得巧,而是它根本不走那条路。线上误在长事务中混用 TRUNCATE,会导致事务提前截断,下游逻辑可能读到中间态数据。











