要快速清空整张表,truncate table是首选;需条件删除、触发器响应或事务回滚时,必须用delete from。truncate是ddl操作,不记行日志、重置自增列、不可回滚;delete是dml操作,逐行记录、支持where和事务。

TRUNCATE比DELETE快得多,但不能回滚、不能带WHERE条件
直接说结论:要快速清空整张表,TRUNCATE TABLE 是首选;如果需要条件删除、触发器响应或事务回滚能力,必须用 DELETE FROM。
根本差异在于执行机制:TRUNCATE 是 DDL 操作,直接释放数据页,不逐行记录日志;DELETE 是 DML 操作,每删一行都记日志、可触发 ON DELETE 规则、受事务控制。
-
TRUNCATE会重置自增列(如 MySQL 的AUTO_INCREMENT、PostgreSQL 的SEQUENCE),DELETE不会 - MySQL 中
TRUNCATE无法在有外键引用的表上执行(报错Cannot truncate a table referenced in a foreign key constraint),DELETE可以(但需满足约束) - SQL Server 和 PostgreSQL 支持
TRUNCATE ... RESTART IDENTITY显式重置序列,MySQL 没这个语法,只能手动ALTER TABLE ... AUTO_INCREMENT = 1
DELETE FROM t1 和 DELETE FROM t1 WHERE 1=1 效果一样,但别这么写
很多人想“安全地清空”,就写 DELETE FROM t1 WHERE 1=1,以为加了 WHERE 就更可控——其实没区别,优化器会全表扫描并删除所有行,性能和 DELETE FROM t1 完全一致,还多打6个字符。
真正要注意的是:没有 WHERE 子句的 DELETE 在 MySQL 默认是禁止执行的(safe_updates=1 时会报错 You are using safe update mode...),这时要么临时关掉:SET SQL_SAFE_UPDATES = 0,要么显式加上主键范围(比如 WHERE id > 0)绕过限制。
- PostgreSQL 和 SQL Server 没这个安全模式,默认允许无
WHERE的DELETE - 哪怕只删 1 行,
DELETE也会锁住整张表(MySQL InnoDB 下是行锁,但全表扫描+全删仍可能升级为表级锁) - 大表用
DELETE清空极易导致 long transaction、日志暴涨、主从延迟,应避免
TRUNCATE 在不同数据库里的权限和行为细节
TRUNCATE 看似简单,但跨数据库时权限要求和副作用差异不小:
- MySQL 要求
DROP权限(不是DELETE权限),因为底层等价于DROP + CREATE表结构 - PostgreSQL 中
TRUNCATE需要表的TRUNCATE权限(9.5+)或OWNER权限,且会级联清空继承子表(除非加ONLY) - SQL Server 允许
TRUNCATE后立刻DBCC CHECKIDENT(..., RESEED, 0)重置种子值,但注意:若表有未提交的插入事务,重置可能失效 - 所有数据库中,
TRUNCATE都不会触发ON DELETE触发器(这是关键区别!如果业务依赖删除触发器发消息或写审计日志,TRUNCATE会跳过)
大表清空的折中方案:分批 DELETE + 空表替换
当既要保留事务/触发器能力,又不能忍受单次 DELETE 锁表太久时,得绕开“全删”思路:
- 先建空表
CREATE TABLE t1_new LIKE t1,再RENAME TABLE t1 TO t1_bak, t1_new TO t1(MySQL 原子操作,毫秒级) - 对超大表,用
DELETE FROM t1 WHERE id BETWEEN ? AND ?分批删,每次删 1 万行,COMMIT后再删下一批(注意id必须有索引,否则BETWEEN仍是全表扫) - PostgreSQL 可用
TRUNCATE ... CASCADE清空主表及所有外键引用表,但务必确认级联关系是否符合预期——它不会提示,删了就没了
最易被忽略的一点:无论用哪种方式,清空后记得 ANALYZE TABLE(MySQL)或 ANALYZE(PostgreSQL),否则优化器统计信息还是旧的,后续查询可能走错执行计划。










