语法错误,缺少比较值或操作符,WHERE子句不完整,无法执行删除操作。

直接执行 DELETE FROM table WHERE created_at 是最危险的批量删除方式——它不加事务控制、不设限、不校验影响行数,极易引发锁表、主从延迟甚至误删全表。
用 ExecuteDelete(EF Core 7+)跳过内存加载
如果你在 .NET 环境中使用 EF Core,别再用 RemoveRange + SaveChanges 删除历史日志或订单明细。那会把十万条记录全加载进内存,再逐条标记删除,87 秒起步,OOM 风险极高。
- 必须确保 EF Core 版本 ≥ 7.0,低版本无此 API
-
ExecuteDelete不触发变更追踪,也不返回实体,只生成原生DELETE语句 - 它支持完整 LINQ 过滤,但不能包含导航属性展开(如
.Include),否则编译失败 - 示例中
context.Logs.Where(...).ExecuteDelete()返回的是受影响行数,不是IQueryable,无法链式调用.ToList()
用 MySQL DELETE ... JOIN 精准清理关联数据
当你要删掉过期订单及其所有子项(比如 orders 和 order_items),单表删两次可能因网络中断或部分失败导致数据不一致。MySQL 的多表 DELETE 语法能在一个事务里完成原子性清理。
- 语法必须显式列出要删的目标表:例如
DELETE o, oi FROM orders o INNER JOIN order_items oi ON o.id = oi.order_id - 只支持
INNER JOIN和LEFT JOIN;RIGHT JOIN会被 MySQL 拒绝 -
LEFT JOIN场景下,若右表无匹配行,左表对应行仍会被删除——这容易误删主表数据,务必加WHERE oi.id IS NOT NULL显式限定 - 外键设了
ON DELETE CASCADE的话,其实不需要手动 JOIN 删除,但得确认级联逻辑是否真符合业务(比如软删场景就不能依赖它)
加限流、分批次、带校验的 Shell 脚本方案
运维同学常写一个脚本定时清日志,但直接跑 mysql -e "DELETE FROM logs WHERE ..." 会堵死线上查询。安全做法是控制每次删 5000 行,并检查实际影响数是否合理。
- 用
SELECT COUNT(*)先估算待删总量,超 10 万就强制走分批 - 每次执行前加
SELECT ROW_COUNT()或捕获$?和输出行数,若为 0 则退出(避免条件写错删空) - 推荐用
mysql_config_editor存登录路径,而不是在脚本里拼-p'xxx'——密码含特殊字符时易被 shell 解析错误,且会出现在ps aux中 - 关键步骤必须加
START TRANSACTION/COMMIT包裹,哪怕只是单条DELETE(InnoDB 默认自动提交,不显式开事务就无法回滚)
真正容易被忽略的是 binlog 日志体积暴增——一次删 50 万行,binlog 可能瞬间涨几百 MB,压垮磁盘或拖慢主从同步。生产环境执行前,先用 SHOW MASTER STATUS 记下当前 binlog 文件和位置,删完立刻 FLUSH LOGS 切新日志,再评估是否需要 PURGE BINARY LOGS 清理旧日志。


















