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
);

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

相关推荐
#六脉神剑14 分钟前
myBuilder新版本(8月,Office文件预览、Oracle数据库支持)
数据库·oracle·开发平台·数字化工具·mybuilder
花青泽17 分钟前
5-数据库-SQL注入-联合查询-AND/OR绕过-day13
数据库·sql
踏着七彩祥云的小丑37 分钟前
忘记Redis是否安装过时查看
数据库·redis·缓存
Nontee2 小时前
设计模式:模板方法与策略,从“每个字都认识“到能说清它们在干嘛
java·数据库·设计模式
眞bilibili2 小时前
带团队后的日常思考(十七)
数据库
laboratory agent开发3 小时前
智能体多工具串联执行中途失败,部分写入的数据如何回滚
运维·服务器·数据库
xqqxqxxq3 小时前
DML 表数据:插入、删除、修改
笔记·mysql
段一凡-华北理工大学3 小时前
AI推动工业智能化转型~系列文章07:分类与诊断算法体系:故障识别的完整工具箱
数据库·人工智能·算法·机器学习·分类·数据挖掘·高炉炼铁智能化
DBA_G3 小时前
南大通用GBase HD数据平台讲解
数据库
foolishlee4 小时前
Neon wal日志处理流程
数据库