不能直接 DELETE FROM table WHERE create_time,因为未加索引会导致全表扫描、锁表时间长;不分批易引发事务过大、OOM或超时;不关autocommit会频繁刷盘、加剧锁竞争。

直接用 DELETE 带 WHERE 条件清空,但必须分批、加索引、关 autocommit,否则容易锁表、OOM 或事务失败。
为什么不能直接 DELETE FROM table WHERE create_time ?
MySQL 5.7 的 InnoDB 在单条 DELETE 中扫描并逐行标记删除,若匹配百万级行:
- 事务日志(undo log)暴涨,可能填满
innodb_log_file_size配置空间,导致报错ERROR 1205 (HY000): Deadlock found when trying to get lock或ERROR 1213 (40001): Deadlock found - 全表扫描无索引时,
WHERE条件走不到索引,实际是全表扫 + 行锁升级为表锁,阻塞所有写入 - 客户端内存可能撑爆(尤其用 MySQL 客户端未设
--quick),或触发max_allowed_packet截断
必须确保 create_time 字段有索引
执行前先确认:
SHOW INDEX FROM your_table_name WHERE Column_name = 'create_time';
如果没有,立刻加(注意别在业务高峰加):
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 若字段允许为 NULL:
ALTER TABLE your_table_name ADD INDEX idx_create_time (create_time); - 若字段是
NOT NULL且常用于范围查询,考虑联合索引,如(status, create_time)(如果常带状态过滤) - 加索引后务必
ANALYZE TABLE your_table_name;更新统计信息,避免优化器误判
分批删除的实操命令(推荐用主键 ID 分片)
比按时间字段分页更稳定——避免时间重复、空洞、或时区偏差问题。假设表有自增主键 id:
- 先查出待删数据的 ID 范围:
SELECT MIN(id), MAX(id) FROM your_table_name WHERE create_time - 然后循环执行(每次删 5000 行):
DELETE FROM your_table_name WHERE id BETWEEN 10000 AND 14999 AND create_time
- 每次执行后加
SLEEP(0.1);(在应用层控制节奏),或用存储过程封装,避免连续高压 - 监控
SHOW PROCESSLIST;和SHOW ENGINE INNODB STATUS\G中的TRX_ROWS_LOCKED,防止长事务堆积
千万别用 TRUNCATE TABLE 替代条件清空
TRUNCATE TABLE 是 DDL 操作,会重置自增计数器、不可回滚、且不走 WHERE 条件——它只清空整张表。误用等于删库跑路预备动作。
真正容易被忽略的是:即使你加了索引、分了批次,如果表上有 ON DELETE CASCADE 外键关联到大子表,每删一行仍会触发子表扫描。此时必须先 SET FOREIGN_KEY_CHECKS = 0;(仅限当前会话),删完再设回 1,但要确保你清楚外键约束语义是否允许跳过级联检查。










