一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

为何MySQL执行DELETE语句比TRUNCATE更容易产生锁等待?

时间:2026-07-16 08:21:52 编辑:袖梨 来源:一聚教程网

DELETE长时间持锁,因其作为DML需逐行加X锁、写undo log、维护MVCC链,全表扫描时锁持续至事务结束;TRUNCATE为DDL,仅瞬时获取SCH_M表级锁并隐式提交,不参与事务锁队列,故几乎无锁等待。

因为DELETE是DML,全程走行级锁+事务机制;TRUNCATE是DDL,只瞬时持表级锁且隐式提交。

DELETE为什么会长时间持有锁

DELETE不是“删完就放锁”,而是边删边锁、边写日志、边维护MVCC版本链:

  • DELETE FROM t 会启动一个事务,对每一行加X锁(或间隙锁),直到事务结束才释放
  • 没WHERE条件时,InnoDB仍要全表扫描聚簇索引,逐行加锁、打删除标记、写undo log
  • 若表无合适索引,可能升级为表锁;高并发下容易出现LOCK_WAIT或死锁
  • SHOW ENGINE INNODB STATUS里常看到大量RECORD LOCKS和长时间Trx has been waiting

TRUNCATE锁等待几乎为零的底层原因

TRUNCATE根本不参与事务锁队列,它压根不“等”锁,只做两件事:抢锁、失败或秒过:

  • 它申请的是SCH_M(schema modification)锁,粒度是表级,但持有时间以毫秒计
  • 一旦发现表被LOCK TABLES t READ或外键引用,立刻报错退出:ERROR 1099ERROR 1701,绝不排队等待
  • 执行即隐式提交,不进事务上下文,所以SELECT FOR UPDATE或其他DML不会因它进入锁等待队列
  • 主从复制中,从库收到的是轻量DDL事件,不会像DELETE那样堆积上万条row event导致应用线程卡住

线上误用TRUNCATE反而引发更隐蔽的问题

看似“不卡锁”很安全,但实际容易踩进事务截断和数据一致性陷阱:

  • 在长事务里执行TRUNCATE TABLE t,MySQL会自动COMMIT当前事务——你后面跟的ROLLBACK完全无效,下游可能读到中间态
  • TRUNCATE重置AUTO_INCREMENT,如果业务依赖ID单调递增(比如对外暴露的订单号),首次插入可能撞上旧ID
  • 它不触发ON DELETE触发器,也不检查外键约束(除非被引用),这些“省略”在某些场景下就是逻辑漏洞

真正决定是否用TRUNCATE的,从来不是“快不快”,而是“能不能接受不可回滚、自增重置、触发器失效、外键拒绝”这四点。锁只是表象,语义差异才是根本。

热门栏目