DELETE比DROP更吃锁资源,因其逐行加行锁、写undo log并更新索引,而DROP仅需短暂持有表级MDL锁且不触碰数据页。

DELETE为什么比DROP更吃锁资源
因为 DELETE 是逐行操作,而 DROP 是元数据级操作 —— 它们根本不在一个锁粒度层级上。
DELETE 在 InnoDB 中默认加的是行锁(或间隙锁、临键锁),每扫描一行、每标记删除一行,都要申请锁、写 undo log、更新聚簇索引和二级索引。如果没加 WHERE 条件,它会全表扫描并尝试锁住所有行(或所有索引范围),极易引发锁等待甚至死锁;若表很大,这个过程可能持续数分钟,期间其他事务读写该表会被阻塞。
DROP TABLE 只需要获取一个表级元数据锁(MDL),且是排他型(MDL_EXCLUSIVE),但它的持有时间极短:只要确认没有活跃事务正在访问该表,就立刻释放 MDL 并异步删文件。它不碰数据页、不写 undo、不更新索引,所以几乎不争抢数据层面的锁资源。
常见错误现象:
- 执行
DELETE FROM big_table后,发现SHOW PROCESSLIST里一堆Waiting for table metadata lock—— 其实不是DELETE自己卡着锁,而是它长时间持有行锁,导致后续 DDL(比如ALTER TABLE)等不到 MDL,反过来把其他查询也拖住 - 误以为
DROP“更重”所以更耗资源,结果发现DROP秒完成,DELETE卡了 20 分钟还只删了一半
什么时候 DELETE 会意外升级成表锁
InnoDB 不会主动升级锁,但某些条件会让 DELETE 实际效果等效于“全表锁”:
- 没走索引的
WHERE条件(例如DELETE FROM t WHERE JSON_CONTAINS(j, '"abc"')且j无函数索引)→ 全表扫描 + 每行加锁 - 使用
ORDER BY ... LIMIT但优化器预估要扫描大量行 → 可能锁住扫描路径上的所有间隙 - 在
READ COMMITTED隔离级别下删大量数据,undo log 膨胀快,触发 purge 线程压力,间接拖慢锁释放
注意:TRUNCATE TABLE 虽然也快,但它用的是 DDL 级 MDL 锁,且不可回滚 —— 所以它不消耗事务锁资源,但会直接拒绝任何并发读写请求,这点和 DROP 类似,但和 DELETE 的“温柔但持久”的锁行为完全不同。
DROP 真的完全不碰事务系统吗
不完全。虽然 DROP TABLE 本身不写 undo log,也不进事务日志(redo log)的数据部分,但它会:
- 写一条 DDL 日志到 redo log(记录“表已删除”元信息)
- 触发 frm 文件和 ibd 文件的异步清理,这部分由后台线程完成
- 如果该表被其他表外键引用,
DROP会直接报错ERROR 1217 (HY000): Cannot delete or update a parent row: a foreign key constraint fails,而不是等锁超时
也就是说,DROP 的“轻量”是建立在它绕过整个数据引擎事务流程的基础上的 —— 它不参与 MVCC、不生成版本链、不维护回滚段。而 DELETE 正好相反:它深度绑定事务生命周期,每一行都是一个独立的可回滚单元。
真正容易被忽略的点是:锁资源消耗不只看“锁了多久”,更要看“锁住了什么”。DELETE 锁的是数据行及其可见性状态,影响所有隔离级别下的并发访问;DROP 锁的只是表定义快照,只要没人正查这张表,它就一闪而过。


















