MySQL 删除数据全方式详解

一、三种核心删除语法:DELETE / TRUNCATE / DROP

1. DELETE 语句(DML 数据操作语言,线上最常用)

1)基础用法

sql

复制代码
-- 删除符合条件的单/多条数据
DELETE FROM product_category WHERE id = 10;

-- 删除整张表全部数据(不推荐,量大性能差)
DELETE FROM product_category;

-- 多条件删除
DELETE FROM order_info WHERE create_time < '2026-01-01' AND is_delete = 0;
关键特性
  1. 只删表内数据,保留表结构、索引、约束
  2. 支持 WHERE 条件精准删除,可回滚(事务中执行可 ROLLBACK);
  3. 自增主键不重置,下一条新增 id 延续之前最大值;
  4. 逐条删除,写入 undo 日志,数据量大时性能极差;
  5. 会触发触发器、逻辑删除拦截、事务锁;
  6. 支持 LIMIT 限制删除行数,避免一次性删百万数据锁表:

sql

复制代码
-- 每次删1000条,分批删除大表数据
DELETE FROM log_info WHERE id < 100000 LIMIT 1000;
适用场景
  • 精准删除单条 / 少量业务数据;
  • 线上删除指定订单、商品、用户;
  • 需要支持事务回滚的删除操作;
  • 保留自增 id 连续性的业务。

2. TRUNCATE TABLE

sql

复制代码
TRUNCATE TABLE product_category;
-- 简写
TRUNCATE product_category;
关键特性
  1. 清空表所有数据,不支持 WHERE 条件,无法删部分数据;
  2. 保留表结构、字段、索引,重置自增主键为 1
  3. 底层直接销毁重建数据页,不记录 undo 日志,速度极快(百万级数据秒清);
  4. 不可回滚,事务中执行也无法撤销;
  5. 会清空统计信息,外键关联表禁止直接 truncate;
  6. 不触发删除触发器。
适用场景
  • 测试环境清空测试表数据;
  • 定期清理独立日志表(无外键、无业务关联);
  • 全新初始化表,需要重置自增 ID。
生产红线

线上业务主表禁止随便执行 TRUNCATE,一旦执行整表数据清空且无法回滚。


3. DROP TABLE

sql

复制代码
DROP TABLE IF EXISTS product_category;
关键特性
  1. 直接删除整张表:数据 + 表结构 + 索引 + 约束全部销毁
  2. 释放磁盘空间,无法恢复(无备份直接丢表);
  3. IF EXISTS 避免表不存在时报错。
适用场景

废弃不用的旧表、历史临时表,确认永久不再使用才执行。

二、业务层「逻辑删除」

原理

不执行任何 DELETE 物理删除 SQL,通过标记字段区分数据是否有效

  1. 表增加字段:is_delete TINYINT DEFAULT 0 COMMENT 0正常 1已删除
  2. 删除操作改为 UPDATE 更新标记:

sql

复制代码
UPDATE product_category SET is_delete = 1 WHERE id = 10;
  1. 查询时强制过滤已删除数据:

sql

复制代码
SELECT * FROM product_category WHERE is_delete = 0;
MyBatis-Plus 自动逻辑删除配置(你项目在用)
  1. yml 全局配置

yaml

复制代码
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: isDelete
      logic-delete-value: 1
      logic-not-delete-value: 0
  1. 实体加注解

java

运行

复制代码
@TableLogic
private Integer isDelete;
  1. 调用 mapper.deleteById(10L),MP 自动执行 UPDATE,不会执行 DELETE。
优势
  • 数据可恢复,防止误删订单、商品等核心业务数据;
  • 支持数据溯源、对账、售后纠纷查询;
  • 避免物理删除带来的锁表、事务风险。
适用场景

电商订单、商品、用户、支付流水、交易类核心业务表(强制逻辑删除)。

三、批量删除优化方案

方案 1:DELETE 分批删除

避免一次性删除几十万行锁表阻塞业务:

sql

复制代码
-- 循环执行,每次删1000条,直到无数据
DELETE FROM operation_log WHERE create_time < '2026-01-01' LIMIT 1000;

方案 2:分表归档 + TRUNCATE

历史日志按月分表,直接 truncate 过期月份分表,不影响主业务表。

方案 3:新建空表替换

  1. 复制原表结构 CREATE TABLE log_new LIKE log_old;
  2. 交换表名 RENAME TABLE log_old TO log_bak, log_new TO log_old;
  3. 备份完成后 DROP 备份表。

四、四种删除方式核心对比表

表格

方式 语法类型 是否删表结构 支持条件 WHERE 自增 ID 可回滚 速度 生产业务表推荐
DELETE DML 保留 ✅支持 不重置 ✅事务可回滚 慢(量大阻塞) 少量精准删除
TRUNCATE DDL 保留 ❌不支持 重置为 1 ❌不可回滚 极快 测试 / 独立日志表
DROP TABLE DDL 全部删除 ❌不支持 ❌不可回滚 废弃无用表
逻辑删除 UPDATE DML 完全保留 ✅支持 不变 ✅可恢复 电商核心业务(首选)

五、生产环境删除数据规范 & 避坑

  1. 核心业务表禁止物理删除(订单、支付、商品、用户),统一逻辑删除;
  2. 执行 DELETE 大批量数据前,先 SELECT 核对删除行数,避免误删;
  3. 线上禁止无 WHERE 的 DELETE FROM 表名,会锁全表;
  4. TRUNCATE 严禁在主业务表执行,执行前必须全量备份;
  5. 删除操作尽量避开业务高峰(凌晨低流量执行);
  6. 外键关联表删除时,先删子表数据,再删主表,防止外键报错;
  7. 误删急救:提前开启 binlog 二进制日志,可通过 binlog 恢复误删数据。

六、补充:关联表级联删除

建表时设置外键 ON DELETE CASCADE,删除主表数据自动同步删除子表关联数据

sql

复制代码
CREATE TABLE order_item(
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    order_id BIGINT,
    FOREIGN KEY (order_id) REFERENCES order_info(id) ON DELETE CASCADE
);

删除订单主表数据,订单明细会自动删除;电商项目不推荐使用,级联删除不可控,容易误删大量数据,业务代码手动控制删除明细更安全。

相关推荐
青山木2 小时前
Redis 高可用的最后一公里:Cluster 分片、Gossip 与故障转移全流程
数据库·redis·后端·缓存
蓝胖的四次元口袋3 小时前
JavaString知识梳理
数据库·oracle
csdn_aspnet3 小时前
mysql 使用逗号拼接一列数据
数据库·mysql·group_concat
952364 小时前
Redis - 基本操作
数据库·redis·spring·缓存
大师兄66684 小时前
HarmonyOS7 数据持久化 relationalStore:数据库实战
数据库·arkui·实战案例·harmonyos7
TDengine (老段)4 小时前
TDengine SMA 索引 — 块级/文件级统计索引
android·大数据·服务器·数据库·人工智能·时序数据库·tdengine
冰茶丿4 小时前
状态机在嵌入式系统中的应用:不只是switch-case这么简单
数据库·嵌入式硬件·mongodb
AIHR数智引擎4 小时前
15%对撞40%:WEF白皮书里的AI组织隐忧
数据库·人工智能·经验分享·职场和发展·aihr
卓怡学长4 小时前
w261springboot基于web学校课程管理系统
java·数据库·spring boot·spring·intellij-idea