truncate几乎不卡锁是因为它作为ddl操作仅需瞬时持有表级x锁且隐式提交,不走事务锁机制;而delete作为dml操作全程持有行锁或间隙锁,受事务控制、mvcc和索引影响,锁持有时间随数据量增长。

TRUNCATE 为什么几乎不卡锁
因为 TRUNCATE TABLE 只需极短时间持有表级排他锁(X lock),释放数据页后立刻释放锁;而 DELETE FROM 在整批删除过程中持续持有行锁或间隙锁,锁持有时间与数据量正相关。千万级表上,DELETE 可能锁表几十秒甚至分钟,TRUNCATE 在毫秒级完成加锁→清空→解锁全过程。
锁类型和粒度差异直接决定阻塞程度
DELETE 默认走行级锁(InnoDB):即使没 WHERE 条件,也会逐行扫描、加锁、打删除标记;若无合适索引,还会升级为表锁。它还要维护 MVCC 版本链,锁资源占用高。TRUNCATE 是 DDL 操作,只申请一次表级 X 锁,用于保证元数据变更安全——不涉及行数据状态变更,无需维护版本链或间隙锁。
- 执行
DELETE FROM t时,SHOW ENGINE INNODB STATUS中常看到大量LOCK_WAIT或RECORD LOCKS - 执行
TRUNCATE TABLE t时,INFORMATION_SCHEMA.INNODB_TRX几乎查不到对应事务记录 - 主从复制中,
DELETE的锁会同步阻塞从库的并发应用线程;TRUNCATE的锁在主库瞬间释放,从库收到的是轻量 DDL 事件
隐式提交让 TRUNCATE 锁无法被事务“包裹”
TRUNCATE 是 DDL,执行即触发隐式提交(implicit commit),当前事务立即结束。这意味着你不能把它放在 BEGIN / ROLLBACK 块里试图控制锁生命周期——它根本不受事务隔离级别约束,也不参与锁等待队列的事务上下文管理。
- 写
BEGIN; TRUNCATE TABLE t; ROLLBACK;,TRUNCATE执行完就已提交,ROLLBACK对它无效,且后续语句属于新事务 -
DELETE则严格遵循事务边界:锁可被ROLLBACK释放,也可被其他事务的SELECT ... FOR UPDATE阻塞 - 线上误在长事务中混用
TRUNCATE,会导致事务提前截断,下游逻辑可能读到中间态数据
外键或显式锁会让 TRUNCATE 直接失败而非等待
TRUNCATE 不会排队等锁,而是遇到冲突立刻报错退出。最常见两类:
-
ERROR 1701 (HY000): Cannot truncate a table referenced in a foreign key constraint—— 表被其他表外键引用,且未开启级联(ON DELETE CASCADE) -
ERROR 1099 (HY000): Table 't' was locked with a READ lock and can't be truncated—— 当前有LOCK TABLES t READ或类似显式锁存在
这两类错误都意味着:它压根不会尝试获取锁,更不会进入锁等待队列。而 DELETE 在同样场景下可能卡住、超时,或因死锁被自动回滚。
真正容易被忽略的是:TRUNCATE 的“快”,建立在它完全绕过事务锁管理机制之上——不是它锁得巧,而是它根本不走那条路。一旦业务需要锁可控、可回滚、可嵌套,就得切回 DELETE,哪怕慢也得认。











