直接DELETE大表卡住是因事务、索引与锁三重压力;应基于有索引的单调字段(如id或create_time)分批删除,避免用LIMIT加OFFSET。
☞☞☞☞点击夸克ai手把手教你,操作像呼吸一样简单!☜☜☜☜☜

DELETE大表卡住,本质是事务+索引+锁三重压力
直接DELETE FROM big_table WHERE create_time 在千万级InnoDB表上,大概率会卡死或拖垮服务。这不是SQL写错了,而是InnoDB在逐行标记删除、同步更新所有索引、维护MVCC版本链、写undo log和redo log——每删一行都在干一堆事。尤其当WHERE字段没索引时,全表扫描+全索引遍历,CPU和I/O双爆。
分批删除必须用“游标式WHERE”,别碰LIMIT offset
常见错误是写成DELETE FROM t WHERE id > 1000000 LIMIT 1000再循环改offset——offset越大越慢,因为MySQL仍要跳过前面所有行。正确做法是基于**有索引的单调字段(如id或create_time)维护边界值**:
- 第一次:
DELETE FROM t WHERE create_time - 查出本次删掉的最大
id(比如SELECT MAX(id) FROM t WHERE create_time ),作为下一批的上限 - 每次执行后加
SLEEP(0.1)(应用层或存储过程中),避免IOPS打满 - 确保
autocommit=1,或显式COMMIT,否则undo log撑爆
索引不是越多越好,删前得做减法
删除性能和索引数量强相关——每删一行,每个二级索引都要更新一次B+树。如果表有5个冗余索引,删除开销直接×5。实操步骤:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 先用
SHOW INDEX FROM your_table列出所有索引 - 检查哪些索引从不被
WHERE/JOIN/ORDER BY使用(可用performance_schema.table_io_waits_summary_by_index_usage查) - 对非必要索引执行
ALTER TABLE your_table DROP INDEX idx_unused - 删除完成后,再根据查询需求重建关键索引,而不是保留全套
TRUNCATE不是万能钥匙,但该用时别犹豫
如果目标是清空整张表(且无外键引用、不依赖触发器、主从复制已同步),TRUNCATE TABLE your_table比任何DELETE都快——它不走事务、不写row log、直接释放段空间。但注意两个硬限制:
-
TRUNCATE会重置AUTO_INCREMENT计数器,如果业务依赖连续ID就不能用 - 有外键引用的表无法
TRUNCATE,报错Cannot truncate a table referenced in a foreign key constraint,此时只能禁用外键检查(SET FOREIGN_KEY_CHECKS = 0)再删,但务必配对恢复
真正容易被忽略的是:删完不OPTIMIZE TABLE,碎片空间不会自动回收;而OPTIMIZE本身在大表上又是重量级操作,得单独安排窗口。










