TRUNCATE比DELETE快,因其是DDL操作,直接释放数据页并重建表结构,不逐行处理;DELETE是DML,需事务、行锁、undo日志和binlog,性能随数据量线性下降。

TRUNCATE 比 DELETE 快,不是因为“写法更优”或“加了索引”,而是它根本没走 DELETE 那条路——它不处理数据行,直接扔掉整块数据页。
TRUNCATE 是 DDL,DELETE 是 DML
这是最根本的分水岭。MySQL 里 TRUNCATE TABLE t 被归为 DDL(数据定义语言),实际执行是隐式地 DROP + CREATE:清空 .ibd 文件链表、重置 segment、重建空聚簇索引。整个过程不访问任何数据页,也不遍历 B+ 树。
DELETE FROM t 则是标准 DML,必须启动事务、逐行扫描聚簇索引、对每行加 X 锁、打 delete bit、写 undo log 和 binlog event——100 万行 = 100 万次锁 + 日志 + 刷盘。
- DDL 操作不进 undo log 缓冲池,
TRUNCATE几乎不产生 undo 日志 - DML 操作必须写满 undo 表空间,大表
DELETE可能触发innodb_force_recovery -
TRUNCATE的 redo log 只记页释放和元数据变更;DELETE的 redo 是逐行变更记录
TRUNCATE 不锁行,但会瞬时锁表
TRUNCATE 确实需要表级排他锁(X lock),但持有时间极短——只够完成元数据切换和文件截断。而 DELETE 的行锁会持续到事务结束,锁住的行数随数据量线性增长。
- 执行中查
SHOW PROCESSLIST,DELETE常卡在Updating或Writing to net状态 - 主从复制下,
binlog_format = ROW时,DELETE生成上万 event,极易引发从库延迟飙升 -
TRUNCATE在 binlog 中只记一条 DDL 事件,从库回放快且无压力
TRUNCATE 重置 AUTO_INCREMENT,DELETE 不重置
这是开发最常踩的坑:TRUNCATE 会把 AUTO_INCREMENT 值强制设回 1(或最小偏移),而 DELETE 后再插入,ID 仍从原最大值 +1 继续。
- 原因在于
TRUNCATE调用的是ha_innobase::truncate(),直接重载dict_table_t::autoinc字段 - 查当前 autoinc 值不能看
SHOW CREATE TABLE,得用:SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='db' AND TABLE_NAME='t' - 若业务依赖 ID 单调递增(比如对外暴露的订单号),
TRUNCATE后首次插入可能撞上旧 ID
TRUNCATE 失败的三个高频原因
别怪命令慢,先看是不是环境没准备好。
-
Cannot truncate a table referenced in a foreign key constraint:外键硬引用。解法:SET FOREIGN_KEY_CHECKS = 0→TRUNCATE TABLE t→SET FOREIGN_KEY_CHECKS = 1 -
TRUNCATE command denied:权限不足。TRUNCATE 需要DROP权限,不是DELETE权限。DBA 得执行:GRANT DROP ON db.t TO 'user'@'%' - 执行后发现“没生效”或“ROLLBACK 无效”:TRUNCATE 是隐式提交,
BEGIN; TRUNCATE TABLE t; ROLLBACK;中的ROLLBACK完全被忽略
真正危险的不是速度,是它太快了——没留给你反悔的时间。删之前确认三件事:外键是否已处理、权限是否到位、自增 ID 是否可重置。否则,快只是假象,恢复成本才是真代价。

















