TRUNCATE日志开销小是因为它不逐行记录,仅写入元数据变更日志(如页释放、自增重置),不生成每行的undo log或binlog事件;而DELETE作为DML需为每一行写入undo log和binlog,日志量随数据量线性增长。
因为 TRUNCATE 不是逐行操作,而是直接释放数据页和分配单元(allocation unit),只记录元数据变更(如页释放、自增列重置),不记录每条被删的行。而 DELETE 是 DML 操作,必须为每一行生成 LOP_DELETE_ROWS 类型日志,用于支持回滚、复制、CDC 等机制。
它确实写日志,但量极少——主要包含:LOP_BEGIN_XACT、LOP_MODIFY_ROW(更新 IAM/PFS 页面)、LOP_DEFERRED_ALLOC(延迟释放标记)等几类操作。用 fn_dblog(NULL, NULL) 查看,1280 行数据被 TRUNCATE 后通常只新增几百条日志,远少于 DELETE 的上万条。
在 MySQL 中,TRUNCATE TABLE 本质是 DROP + CREATE 表(尤其在非临时表且无外键时),因此会写 binlog(语句格式或行格式取决于 binlog_format),也会触发 redo log 记录页释放和字典变更,但不写 undo log —— 所以不可回滚。这点和 SQL Server 的“仅元数据日志”逻辑一致,但实现路径不同。
即使日志少,TRUNCATE 仍受硬性约束:
• 需要 ALTER 权限,不是 DELETE 权限;
• 若表被外键引用(哪怕引用表为空),直接报错;
• 无法在显式事务中回滚(SQL Server/MySQL 均如此,PostgreSQL 除外);
• 不触发 ON DELETE 触发器,业务逻辑可能意外跳过。