DELETE + ORDER BY 锁更死,是因为ORDER BY无法走索引时触发全表扫描并为每行加next-key lock,导致大面积锁表;根本原因在于索引设计不当或排序字段未被覆盖。

DELETE + ORDER BY 为什么反而锁得更死?
DELETE 语句加 ORDER BY 本意是想控制删除顺序、配合 LIMIT 分批,但若索引设计或写法不当,它会直接触发全表扫描和大面积加锁——不是“慢”,而是“锁住所有能碰的行”。
关键原因在于:InnoDB 在 REPEATABLE READ 隔离级别下,ORDER BY 若无法走索引,优化器就会放弃索引查找路径,转而遍历聚簇索引(主键 B+ 树)做 filesort。这个过程每扫一行就加一把 next-key lock(记录锁 + 间隙锁),最终锁住的范围可能覆盖整张表。
-
EXPLAIN DELETE FROM t WHERE status = 'old' ORDER BY id中如果type是ALL或key为NULL,基本等于宣告要锁表 - 即使
status有索引,但ORDER BY id的id不在该索引中(比如没建联合索引(status, id)),优化器仍可能拒绝使用索引 -
ORDER BY ABS(created_at)、ORDER BY CONCAT(a, b)这类函数包裹字段,索引必然失效,强制全表扫描
哪些 ORDER BY 实际上不走索引?
不是写了 ORDER BY 就能用上索引。真正能避免锁膨胀的,只有那些能被索引天然覆盖排序顺序的写法。
- 索引字段必须是最左前缀连续出现:有联合索引
INDEX(status, created_at, id),则ORDER BY status, created_at可走索引;但ORDER BY created_at, id不行 - 排序方向需一致:
ORDER BY status ASC, created_at DESC若索引是(status ASC, created_at ASC),则created_at部分无法利用索引 - 不能混用 ASC/DESC:
INDEX(a ASC, b DESC)是有效索引,但 MySQL 8.0 之前不支持混合方向索引的排序优化 -
WHERE条件字段未出现在索引中时,ORDER BY索引再好也白搭——优化器不会为纯排序单独走一遍索引
正确写法:ORDER BY 必须锚定在索引最左列
想让 DELETE ... ORDER BY ... LIMIT 安全执行,核心是让整个查询只访问最小必要索引范围,且加锁可控。
必须确保
WHERE和ORDER BY共享同一个覆盖索引,例如:DELETE FROM logs WHERE status = 'archived' ORDER BY id LIMIT 1000
要求存在索引INDEX(status, id),且id是单调递增主键或时间戳绝对不要用
LIMIT 10000, 5000这类 offset 分页:偏移越大,MySQL 越可能放弃索引,改走全表扫描+临时文件排序如果没有合适联合索引,宁可先
SELECT id FROM t WHERE status = 'old' ORDER BY id LIMIT 1000拿到 ID 列表,再用DELETE WHERE id IN (...)——虽然多一次查询,但锁粒度精准、可预测
并发批量删时 ORDER BY 顺序不一致会死锁
两个事务同时执行类似 DELETE FROM orders WHERE id IN (105, 102, 108) ORDER BY id,看似安全,但实际加锁顺序取决于数据物理分布。若事务 A 按索引顺序锁 102→105→108,事务 B 锁 105→102→108,就可能形成循环等待。
- 最稳妥做法是显式排序后拼接:先
SELECT id FROM orders WHERE id IN (105,102,108) ORDER BY id,取结果再构造DELETE ... WHERE id IN (102,105,108) - 更高阶方案是用子查询固化顺序:
DELETE FROM orders WHERE id IN (SELECT id FROM (SELECT id FROM orders WHERE id IN (105,102,108) ORDER BY id) t) - 所有批量删操作,务必在事务内完成,且避免混入 HTTP 请求、日志写入等非 DB 操作——锁会一直挂着,直到事务提交或回滚
真正危险的不是 ORDER BY 本身,而是它暴露了索引缺失、执行计划失控、事务边界模糊这些底层问题。线上执行前,一定先 EXPLAIN 看 key 和 rows_examined,别信“我只删 1000 行所以没问题”这种直觉。

















