一条 DELETE 忘了写 WHERE,回车之后 Query OK,几万行数据没了。这种事故每年都能见到几次,恢复的时候只能靠备份和 binlog。

mysql delete 的标准写法是 DELETE FROM 表名 WHERE 条件 LIMIT 行数。执行前先把 DELETE 换成 SELECT COUNT(*),同样的条件跑一遍,看清楚会影响多少行再动手。WHERE 条件最好走索引,不然几百万行的表会锁很久。

先备份,再开事务

大表删除前用 mysqldump 导一份,或者至少确认 binlog 是开着的。InnoDB 里的 DELETE 可以回滚,删完先别提交,SELECT 确认数据不对就 ROLLBACK,对上了再 COMMIT。DELETE 语句里能用 ORDER BY 加 LIMIT,按 id 排序删一批。

DELETE、TRUNCATE、DROP 的区别

DELETE 逐行删,能带 WHERE,能回滚,速度慢。TRUNCATE 直接清空整表,不能带条件,自增 ID 归零,多数情况下不可回滚;DROP 连表结构一起没。

清空整表优先 TRUNCATE,别用 DELETE 硬删几百万行。DELETE 删完磁盘空间不会马上还给系统,InnoDB 要重建表才回收,别以为没删干净。TRUNCATE 会隐式提交,事务里包不住。

报错 1175 和删不动的行

MySQL 客户端开了安全更新模式,没带主键条件的 DELETE 会报 1175,要么补上 WHERE 主键,要么临时 SET SQL_SAFE_UPDATES = 0,用完记得改回来。有外键约束的表,先处理子表数据,不然怎么删都失败。

业务表更常见的是逻辑删除,加一个 is_deleted 字段,查询时过滤,数据留着能追溯。线上大表别一次删完,按主键分批,每次几千行,中间 sleep 一下,锁表和主从延迟都能缓一缓。删完记得 ANALYZE TABLE,统计信息更新,执行计划才不会跑偏;主从环境先确认延迟,别在从库追数据的时候删,mysql delete 写起来简单,真正要练的是删之前的确认习惯。