delete不加where会清空整张表且不可逆;必须先用select验证条件、开启事务人工审核、推荐标记删除而非物理删除,limit仅限单表且不保证顺序。

必须加 WHERE,否则整张表数据全丢——这是生产环境最常踩的坑。
DELETE不加WHERE会怎样
执行 DELETE FROM users; 不报错,但会立刻删光 users 表所有行。InnoDB 会逐行标记删除、写 undo log,事务可回滚,但没人会在出事时靠回滚救火。
- 没有备份 + 没开 binlog + 直接提交 = 数据永久丢失
- 即使开了 binlog,恢复也要停服务、重放日志,耗时且风险高
- MyISAM 更危险:不支持事务,删了就真没了
先查再删,用同一条件验证
别信记忆里的 WHERE 条件,每次都要亲手 SELECT 一遍:
SELECT id, name, created_at FROM orders WHERE status = 'cancelled' AND created_at
- SELECT 和 DELETE 的
WHERE必须完全一致,复制粘贴,别手敲 - 如果涉及时间字段,注意时区(
NOW()vsUTC_TIMESTAMP()) - 大表建议加
LIMIT 10先试删几行,看影响是否符合预期
多表关联删除的两种写法
MySQL 支持两种语法,但行为和兼容性不同:
JOIN 写法(推荐,高效):
DELETE o, od FROM orders o JOIN order_details od ON o.order_id = od.order_id WHERE o.status = 'refunded';
子查询写法(兼容老版本,但可能慢):
DELETE FROM order_details WHERE order_id IN (SELECT order_id FROM orders WHERE status = 'refunded');
- JOIN 写法能走索引,避免子查询的重复扫描;但只适用于 MySQL
- 子查询在
IN中若返回 NULL,整条语句可能不匹配(加IS NOT NULL防御) - 外键设了
ON DELETE CASCADE的话,删主表会自动连带删子表,无需手动写多表 DELETE
LIMIT 分批删大表,别硬刚
删几十万行以上时,单次 DELETE 会锁表久、undo log 爆涨、主从延迟飙升:
DELETE FROM logs WHERE created_at
- 每次删 5000 行,循环执行,两次之间
SLEEP(0.1)降低压力 - 务必确保
WHERE字段有索引,否则LIMIT也救不了全表扫描 - 别用
ORDER BY id DESC LIMIT 5000删旧数据——没索引时性能极差,应改用时间字段+索引
真正容易被忽略的是:删完后 ibdata1 文件不会自动缩小,InnoDB 表空间得靠 OPTIMIZE TABLE 或迁移重建才能回收,但这操作本身又会锁表——所以大删前,先评估磁盘和维护窗口。











