会,但只在数据量大时才明显;删百万行以上会导致全表扫描、锁表、binlog膨胀、主从延迟加剧,必须加created_at索引并分批删除。

直接用 DELETE FROM ... WHERE 会出事吗?
会,但只在数据量大时才明显。比如删百万行以上,DELETE FROM logs WHERE created_at 一跑就锁表、慢、可能触发事务超时或日志写爆。InnoDB 对大范围删除非常敏感,不是语法错,是引擎底层行为导致的——它要逐行标记、维护索引、写 undo log。小表(几万行以内)可以直删;大表必须干预。
分批删时 LIMIT 值设多少才安全?
500–2000 是生产环境最常验证过的区间,不是越大越好。原因:
• LIMIT 10000 看似快,但单次锁行时间长,容易阻塞其他业务 SQL
• LIMIT 100 太小,网络和事务开销占比高,总耗时反而上升
• 推荐从 LIMIT 500 起步,在低峰期实测:执行一次 + 查 ROW_COUNT() + SLEEP(0.1),观察慢查询日志和 SHOW PROCESSLIST 中的锁等待
为什么不能用多线程并发删同一张表?
容易触发死锁和主键冲突,尤其当条件涉及非唯一索引时。MySQL 的行锁机制在并发 DELETE 下会争抢间隙锁(gap lock),而 WHERE create_time 这类范围条件正是间隙锁高发区。现象包括:<br>• 错误信息:<code>Deadlock found when trying to get lock
• 部分连接卡住,SHOW ENGINE INNODB STATUS 显示锁等待链
• 实际删除量远小于预期(部分被回滚)
真正有效的并发策略是:按主键分段,每个线程处理互不重叠的 id BETWEEN x AND y 区间,且确保该字段有索引
删完发现自增 ID 没重置,正常吗?
完全正常。DELETE 不影响 AUTO_INCREMENT 计数器,这是 InnoDB 的设计行为。如果你需要重置,得手动执行:ALTER TABLE table_name AUTO_INCREMENT = 1。但注意:这个操作会锁表(即使只是元数据锁),且重置值必须大于当前最大 ID,否则插入新记录时会报错 Duplicate entry。更稳妥的做法是别动它——除非你明确知道后续不会插入旧 ID 冲突的数据。
实际删之前,先用 SELECT COUNT(<em>)</em> 和 EXPLAIN 确认条件走索引,再用 SELECT LIMIT 10 看样例数据。删的过程里,监控 innodb_row_lock_waits 和 slow_query_log 比盯着进度数字有用得多。











