mysql执行delete语句顺序是什么_mysql删除操作流程解析

来源:这里教程网 时间:2026-02-28 20:50:58 作者:

MySQL DELETE 语句到底按什么顺序执行

不是“找到就删”,而是一套受事务、锁、日志和存储引擎严格约束的多阶段流程。InnoDB 下典型 DELETE 的实际执行顺序是:

SQL解析 → 权限校验 → 加锁(next-key lock)→ 查找聚簇索引记录 → 写undo log + redo log → 标记记录为删除(purge延迟物理清除)→ 提交事务释放锁
。这个顺序决定了为什么没索引会锁全表、为什么删完磁盘空间不减少、为什么大删容易卡住主从。

为什么加锁发生在“查找记录”之前而不是之后

加锁不是为了保护“要删的数据”,而是为了防止其他事务在你执行过程中插入幻行(幻读),所以 InnoDB 默认对 WHERE 条件匹配的**索引范围**提前加 next-key lock(记录锁 + 间隙锁)。这意味着:

DELETE FROM t WHERE id = 100
(主键精确匹配)→ 只加 record lock,锁单行
DELETE FROM t WHERE status = 1
(非唯一索引)→ 锁所有
status = 1
的行 + 它们之间的间隙,可能锁住上千行
没走索引(如
WHERE create_time  但该字段无索引)→ 全表扫描 + 全表加锁 → 极易阻塞甚至死锁

执行前务必用

EXPLAIN
确认是否命中索引,否则补索引比调优 SQL 更有效。

删完数据,磁盘空间为什么一点没少

InnoDB 不会把删掉的页还给操作系统,只是把记录标记为“已删除”,空间保留在 .ibd 文件内供后续 INSERT 复用。所以:

DELETE FROM huge_log WHERE ts  执行完,<code>du -h
看 .ibd 文件大小完全不变
真正释放空间必须重建表:
ALTER TABLE huge_log ENGINE=InnoDB
OPTIMIZE TABLE huge_log
8.0+ 虽支持 online DDL,但
OPTIMIZE
仍会触发 copy table 阶段,I/O 和 CPU 压力陡增,线上慎用
更稳妥的做法是分批删 + 定期归档,而非强求即时 shrink

大表删旧数据,怎么写才不拖垮数据库

直接

DELETE FROM orders WHERE created_at  是高危操作:它会生成巨量 undo log、撑爆 binlog、拉长事务、导致从库延迟数小时。安全做法是控制节奏和粒度:

用主键分片:例如每次删
id BETWEEN 1000000 AND 1000999
,配合
LIMIT 1000
SLEEP(0.1)
控制节奏(应用层实现),避免连续 I/O 打满磁盘
优先用
SELECT id FROM ... ORDER BY id LIMIT 1000
先取 ID,再
DELETE WHERE id IN (...)
,避免重复扫描
确认
binlog_format = ROW
,否则基于语句的 binlog 在从库可能因时间函数或非确定性排序导致不一致

最常被忽略的一点:删完别忘了

ANALYZE TABLE
。统计信息过期会导致后续查询走错索引,问题可能在几天后才暴露。

相关推荐