2.14 sql数据删除(DELETE、TRUNCATE)

2.14 数据删除(DELETE、TRUNCATE)

这一章我会带你彻底搞懂SQL中删除数据的两大利器:DELETETRUNCATE。学完之后,你能安全地清理无效订单、测试数据,并能区分什么时候用DELETE,什么时候用TRUNCATE

学习前准备:

  • 已完成MySQL安装(参考系列前几章)

  • 已安装DBeaver或Navicat

  • 准备一个练习数据库,比如delete_demo

学习前环境准备

步骤1:确保MySQL服务已启动。

步骤2:创建练习数据库和表。

sql 复制代码
CREATE DATABASE delete_demo
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

USE delete_demo;

-- 订单表
CREATE TABLE orders (
    order_id VARCHAR(50) PRIMARY KEY,
    user_id INT NOT NULL,
    amount DECIMAL(10,2) NOT NULL,
    order_status TINYINT NOT NULL DEFAULT 1 COMMENT '1待支付,2已支付,3已取消,4已完成',
    create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 用户表
CREATE TABLE users (
    user_id INT PRIMARY KEY,
    user_name VARCHAR(50)
);

-- 插入测试数据
INSERT INTO users (user_id, user_name) VALUES (1, '张三'), (2, '李四'), (3, '王五');

INSERT INTO orders (order_id, user_id, amount, order_status, create_time) VALUES
('ORD001', 1, 299.00, 2, '2025-06-01 10:00:00'),
('ORD002', 2, 189.00, 1, '2025-06-01 11:00:00'),
('ORD003', 3, 599.00, 3, '2025-06-02 09:30:00'),
('ORD004', 1, 399.00, 2, '2025-06-03 14:20:00'),
('ORD005', 2, 99.00, 4, '2025-06-04 16:00:00');

DELETE与TRUNCATE的基础认知

3.1 核心定义

  • DELETE :逐行删除数据,支持WHERE条件,可以回滚(在事务中)。删除速度慢,但更灵活。

  • TRUNCATE :清空整张表,不支持WHERE条件,不能回滚(在MySQL中默认自动提交)。删除速度快,相当于DROP后重建表。

3.2 核心区别

对比维度 DELETE TRUNCATE
是否支持WHERE ✅ 支持 ❌ 不支持(只能全表清空)
是否可回滚 ✅ 在事务中可以ROLLBACK ❌ 默认自动提交,不可回滚
执行速度 慢(逐行操作) 快(重建表)
自增列计数 不重置,继续从上次最大值+1 重置为1
触发器触发 会触发DELETE触发器 不触发触发器
锁粒度 行级锁 表级锁
磁盘空间 不释放(只是标记删除) 立即释放

3.3 电商场景下的适用选择

  • 删除特定条件的行(如超时未支付订单) :用DELETE

  • 清空临时表或测试表 :用TRUNCATE

  • 删除大批量数据且需要释放磁盘空间 :用TRUNCATE(如果全表清空)或分批DELETEOPTIMIZE TABLE

我的踩坑经历 :有一次我想清空一张临时表,用了DELETE FROM temp_table,没有加WHERE。虽然删光了数据,但表占用的磁盘空间没释放,而且自增ID还在增长。后来改用TRUNCATE temp_table,空间释放了,ID也重置了。清空整张表,用TRUNCATE比DELETE更合适

带WHERE条件的精准删除

4.1 基础语法

sql 复制代码
DELETE FROM 表名 WHERE 条件;

4.2 电商实操案例

案例一:删除超时未支付的订单

电商规则:超过30分钟未支付的订单自动取消,需要从订单表中删除(或标记为取消)。这里演示物理删除。

sql 复制代码
-- 删除30分钟前创建的待支付订单
DELETE FROM orders 
WHERE order_status = 1 AND create_time < NOW() - INTERVAL 30 MINUTE;

案例二:删除指定用户的测试订单

sql 复制代码
-- 删除用户ID为999的测试订单
DELETE FROM orders WHERE user_id = 999;

案例三:删除特定时间段内的已取消订单

sql 复制代码
-- 删除2024年之前已取消的订单
DELETE FROM orders 
WHERE order_status = 3 AND create_time < '2024-01-01';

4.3 安全操作黄金法则(再次强调)

执行DELETE前,必须先用相同的WHERE条件执行SELECT,确认要删除的行数正确

sql 复制代码
-- 第一步:查看要删除的数据
SELECT * FROM orders WHERE order_status = 3 AND create_time < '2024-01-01';

-- 第二步:执行删除
DELETE FROM orders WHERE order_status = 3 AND create_time < '2024-01-01';

-- 第三步:验证删除结果(可选)
SELECT COUNT(*) FROM orders WHERE order_status = 3 AND create_time < '2024-01-01'; -- 应为0

4.4 限制删除行数(LIMIT)

MySQL支持DELETE语句中使用LIMIT,限制删除的行数,分批删除可避免锁表过久。

sql 复制代码
-- 每次只删除1000条超时订单
DELETE FROM orders WHERE order_status = 1 AND create_time < NOW() - INTERVAL 30 MINUTE LIMIT 1000;

可以循环执行直到影响行数为0。

实操避坑提醒DELETE中如果使用了LIMITORDER BY不是必须的,但为了可预测性,建议加上ORDER BY。另外,LIMIT在删除时可能造成"跳过"数据,如果表在并发写入,最好配合主键排序。

全表数据删除:DELETE无WHERE 与 TRUNCATE

5.1 DELETE无WHERE(全表删除)

sql 复制代码
DELETE FROM orders;
  • 特点:删除所有行,但表结构、索引、自增ID起始值保留(继续递增)。速度慢,支持事务回滚。

5.2 TRUNCATE(清空表)

sql 复制代码
TRUNCATE TABLE orders;
  • 特点:快速清空所有行,自增ID重置为1,释放磁盘空间,不支持回滚(在MySQL中默认提交)。

5.3 分步操作对比

使用DELETE清空测试表

sql 复制代码
START TRANSACTION;
DELETE FROM orders_test;
-- 检查结果,如果正确则COMMIT,否则ROLLBACK
COMMIT;

使用TRUNCATE清空测试表

sql 复制代码
TRUNCATE TABLE orders_test;

5.4 电商场景实操:清空临时表

大促期间,每小时会创建临时表orders_hour存储实时数据,处理完后需要清空。

sql 复制代码
-- 推荐用TRUNCATE
TRUNCATE TABLE orders_hour;

5.5 避坑提醒

  • TRUNCATE不能回滚,执行前必须确认是测试环境或已备份。

  • TRUNCATE会重置自增ID,如果业务依赖ID连续性,慎用。

  • TRUNCATE不会触发DELETE触发器,如果表上有外键约束且子表有数据,可能无法执行(取决于外键设置)。

我的踩坑经历 :有一次我准备清空一张生产环境的临时表,用了TRUNCATE,结果发现这张表有外键被其他表引用,执行失败。后来改用DELETE逐行删除才成功。TRUNCATE遇到外键约束时可能失败,需要先处理子表数据或临时禁用外键检查

关联表删除

6.1 使用子查询删除

电商场景:删除所有没有关联用户的订单(孤儿订单)。

sql 复制代码
DELETE FROM orders 
WHERE user_id NOT IN (SELECT user_id FROM users);

注意 :MySQL中,DELETE的子查询不能直接引用被删除的表(某些版本会报错),可以用多表删除语法绕过。

6.2 使用多表JOIN删除(推荐)

语法

sql 复制代码
DELETE 别名1, 别名2 FROM 表1 别名1 JOIN 表2 别名2 ON 条件 WHERE 筛选;

电商场景一:删除用户及其所有订单(级联删除)

sql 复制代码
-- 删除用户ID为1的用户及其所有订单
DELETE u, o FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE u.user_id = 1;

电商场景二:删除没有订单的用户

sql 复制代码
DELETE u FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;

电商场景三:删除已取消订单中的无效商品明细(假设有订单明细表)

先创建订单明细表示例:

sql 复制代码
CREATE TABLE order_items (
    item_id INT PRIMARY KEY AUTO_INCREMENT,
    order_id VARCHAR(50),
    product_name VARCHAR(100),
    FOREIGN KEY (order_id) REFERENCES orders(order_id)
);

INSERT INTO order_items (order_id, product_name) VALUES
('ORD003', '测试商品'),
('ORD003', '另一个商品');

删除已取消订单对应的明细:

sql 复制代码
DELETE oi FROM order_items oi
JOIN orders o ON oi.order_id = o.order_id
WHERE o.order_status = 3;

6.3 分步操作

  1. 先用SELECT验证关联结果。

  2. SELECT改为DELETE,注意指定要删除的表别名。

  3. 执行并验证。

sql 复制代码
-- 验证
SELECT oi.* FROM order_items oi
JOIN orders o ON oi.order_id = o.order_id
WHERE o.order_status = 3;

-- 删除
DELETE oi FROM order_items oi
JOIN orders o ON oi.order_id = o.order_id
WHERE o.order_status = 3;

实操避坑提醒 :多表删除时,DELETE后面跟的是要删除的表的别名,不是*。如果要同时删除多表数据,用逗号分隔别名(如DELETE u, o FROM ...)。务必确认哪些表需要删除,避免误删。

综合实操案例:年度历史无效测试数据清理

7.1 案例背景

某服饰类目电商店铺需要进行数据清理,任务包括:

  1. 删除所有2023年之前创建的、状态为"已取消"的订单。

  2. 删除超过1年未登录的用户(假设有last_login_time字段,这里简化用user_id不在新订单中出现)。

  3. 清空临时表temp_order_import中的数据(使用TRUNCATE)。

  4. 删除没有关联订单的用户(孤儿用户)。

7.2 准备工作

添加必要的字段和测试数据。

sql 复制代码
-- 添加last_login_time字段(模拟)
ALTER TABLE users ADD last_login_time DATETIME DEFAULT NOW();
UPDATE users SET last_login_time = '2023-01-01' WHERE user_id = 3; -- 模拟老用户

-- 创建临时表
CREATE TABLE temp_order_import LIKE orders;
INSERT INTO temp_order_import SELECT * FROM orders WHERE 1=0; -- 空表

7.3 分步操作

步骤1:删除2023年前的已取消订单

sql 复制代码
-- 先查看
SELECT * FROM orders WHERE order_status = 3 AND create_time < '2023-01-01';

-- 删除
DELETE FROM orders WHERE order_status = 3 AND create_time < '2023-01-01';

步骤2:删除超过1年未登录的用户(假设条件:用户没有在最近一年的订单中出现)

sql 复制代码
-- 查看孤儿用户
SELECT u.* FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;

-- 删除
DELETE u FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;

步骤3:清空临时表

sql 复制代码
TRUNCATE TABLE temp_order_import;

步骤4:验证清理结果

sql 复制代码
-- 检查订单表行数
SELECT COUNT(*) FROM orders;

-- 检查用户表行数
SELECT COUNT(*) FROM users;

7.4 合规提示

📌 电商数据合规红线

  • 删除用户数据前,必须确认符合数据保留政策。例如,用户注销后,根据《个人信息保护法》,数据保留不应超过必要期限。删除前应确认是否有未结订单或法律义务。
  • 禁止物理删除生产核心表数据 。推荐采用"软删除"(增加is_deleted字段标记),便于审计和恢复。
  • 删除操作必须记录日志:包括操作人、时间、删除条件、影响行数。重要删除需审批。

本章踩坑清单与合规总结

8.1 新手常见踩坑

错误 后果 正确做法
DELETE忘加WHERE 全表数据丢失 先写WHERE,先SELECT验证
使用TRUNCATE删除子表有外键依赖 报错 先删除子表数据,或临时禁用外键检查
批量删除大表无LIMIT 锁表过久,影响业务 分批删除(如每次1000行)
多表删除时DELETE后写了* 语法错误 写要删除的表别名
删除前不备份 误删无法恢复 备份:CREATE TABLE backup LIKE 原表; INSERT INTO backup SELECT * FROM 原表;

8.2 安全删除最佳实践

  1. 永远先备份CREATE TABLE orders_backup_20250401 AS SELECT * FROM orders WHERE 条件;

  2. 开启事务START TRANSACTION; → 执行DELETESELECT验证 → COMMIT;ROLLBACK;

  3. 限制删除行数 :大表用LIMIT分批删除,避免长事务。

  4. 检查外键依赖 :删除父表数据前,确认子表已处理或使用ON DELETE CASCADE

  5. 生产环境删除必须走审批

8.3 电商数据合规提示

  • 软删除优于硬删除 :在订单表、用户表中增加is_deleted字段,默认0。查询时加上WHERE is_deleted = 0。这样数据可追溯,满足合规审计要求。

  • 删除用户数据需满足"最小必要"原则:只删除不再需要的字段,而不是整条记录。

  • 定期归档而非删除:历史数据可以移到归档库或冷存储,而不是直接物理删除。

结语

DELETETRUNCATE是数据生命周期管理的重要工具。掌握它们,你就能安全地清理无效数据、归档历史记录。但永远记住:删除操作不可逆,谨慎是唯一的安全带。

有问题的评论区留言,我看到会回复。

相关推荐
Lyyaoo.18 分钟前
Redisson
数据库·缓存
网络工程小王25 分钟前
【LCEL 链式调用详解】调用篇-2
java·服务器·前端·数据库·人工智能
道法自然,人法天1 小时前
PostgreSQL安装与初始化教程(二进制压缩包)
数据库·postgresql
yzs872 小时前
从Hydra到storage_engine:PostgreSQL列存引擎的性能跃迁与技术进化
数据库·postgresql
红云梦2 小时前
官方 Anthropic Postgres MCP Server 存在 SQL 注入漏洞 -- SafeDB 是如何做到 4 层防御的
数据库·sql
TDengine (老段)2 小时前
红有软件重构智能油田时序数据底座,支撑生产实时感知与设备预测性维护
大数据·数据库·人工智能·重构·时序数据库·tdengine
倒霉蛋小马2 小时前
【Redis】什么是缓存击穿?
数据库·redis·缓存
Jing_jing_X3 小时前
MCP (一)是什么?一文讲清 AI 如何连接现实世界
数据库·人工智能·oracle
阿凡观察站3 小时前
2026年工程项目管理软件推荐:这5款主流产品值得关注
大数据·数据库·低代码·finebi·简道云
逸Y 仙X3 小时前
文章二十一:ElasticSearch 词项查询与调度查询实战
java·大数据·数据库·elasticsearch·搜索引擎