删除数据 DELETE 与 TRUNCATE
本教程共 46 篇 · 第 18 篇 · 更新于 2026-07-30 · 约 10 分钟阅读
18. 删除数据 DELETE 与 TRUNCATE
本节目标:学会删除表中的数据,掌握 DELETE 按条件删、DELETE JOIN 跨表删、TRUNCATE 清空整表三种方式,理解它们的核心区别和各自适用场景,并了解外键级联删除的工作原理。
18.1 DELETE:按条件删除
DELETE 用来删除表中的行。基本语法:
DELETE FROM 表名
WHERE 条件;
比如删除 id 为 5 的用户:
DELETE FROM users
WHERE id = 5;
执行后返回:
Query OK, 1 row affected (0.01 sec)
跟 UPDATE 一样,WHERE 是关键。忘了写 WHERE,整张表的数据全删光:
-- 危险!删除 users 表所有数据
DELETE FROM users;
Warning和 UPDATE 一样,DELETE 不写 WHERE 就是全表删除。建议开启
--safe-updates模式,强制要求 WHERE 条件。我之前见过一个同事在生产环境执行了无 WHERE 的 DELETE,几百万条数据瞬间清空,幸好有备份。
用 LIMIT 限制删除量
大批量删除时,可以分批删,避免长时间锁表:
-- 每次删 1000 条
DELETE FROM orders
WHERE status = 'expired'
LIMIT 1000;
反复执行直到返回 0 行即可。也可以配合 ORDER BY 控制删除顺序:
DELETE FROM orders
WHERE status = 'expired'
ORDER BY created_at ASC
LIMIT 1000;
Tip删大表数据时,千万别一条 DELETE 删几十万行。分批删,每批 1000-5000 行,中间加个短暂 sleep,给数据库喘口气。
18.2 DELETE JOIN:跨表删除
跟 UPDATE JOIN 类似,DELETE 也能配合 JOIN,根据另一张表的条件来删除。
语法上需要指定从哪个表删:
DELETE o
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE u.age < 18;
这句话的意思是:删除所有”用户年龄小于 18”的订单。
注意 DELETE 后面的 o—它指定只删 orders 表的行,不删 users 表。
同时删多张表的行
如果你想在一次操作中同时删两张表的行,把两个表别名都写在 DELETE 后面:
DELETE o, u
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE u.username = '测试用户';
这会同时删掉”测试用户”的订单记录和用户记录。
Note同时删多表时,JOIN 条件决定哪些行匹配。匹配到的行从各自表里删除,没匹配到的不受影响。用之前务必
SELECT验证一下匹配结果,确认要删的就是这些。
18.3 TRUNCATE:清空整表
TRUNCATE 用来一次性删除表中的所有数据,速度比 DELETE FROM 表名 快得多:
TRUNCATE TABLE orders;
执行后,orders 表里的数据全部消失,但表结构(列、索引、约束)都还在。
为什么 TRUNCATE 比 DELETE 快?原理不同:
DELETE逐行删除,每删一行都要记日志、检查约束,相当于逐行操作TRUNCATE直接释放数据页,不逐行操作,日志只记一条”清空了这张表”
Tip清空测试数据时,用 TRUNCATE 比 DELETE 快几十倍。但记住,TRUNCATE 只能清整张表,不能加 WHERE 条件。
18.4 DELETE vs TRUNCATE 核心区别
这是面试常考的知识点,也是实际操作中必须分清的:
| 对比项 | DELETE | TRUNCATE |
|---|---|---|
| 删除方式 | 逐行删除 | 直接释放数据页 |
| 速度 | 慢(逐行记日志) | 快(只记一条日志) |
| WHERE 条件 | 支持 | 不支持 |
| 事务回滚 | 可以回滚(在事务中) | 不可回滚(隐式提交) |
| 自增计数器 | 不重置 | 重置为初始值 |
| 触发器 | 触发(AFTER/BEFORE DELETE) | 不触发 |
| 返回删除行数 | 返回 affected rows | 返回 0(不统计) |
| 外键约束 | 受外键约束检查 | 若被外键引用则拒绝执行 |
| 权限 | 需要 DELETE 权限 | 需要 DROP 权限 |
几个关键点展开说明:
事务和回滚
DELETE 在事务中可以回滚:
BEGIN;
DELETE FROM users WHERE id = 1;
-- 发现删错了,回滚
ROLLBACK;
-- 数据又回来了
但 TRUNCATE 是隐式提交(auto-commit)的,执行后无法回滚:
BEGIN;
TRUNCATE TABLE orders;
ROLLBACK;
-- 数据回不来了!TRUNCATE 已经提交了
Warning不要指望用事务来保护 TRUNCATE 操作。一旦执行,数据就真没了。用 TRUNCATE 前务必确认。
自增计数器
DELETE 删完数据后,自增列的计数器不会变。比如自增到 100,删了所有行,下次插入还是从 101 开始。
TRUNCATE 会把自增计数器重置回初始值(通常是 1):
-- DELETE 删完后
DELETE FROM users;
INSERT INTO users (username, email, age) VALUES ('新用户', 'new@example.com', 20);
-- 新行 id = 101(继续之前的计数)
-- TRUNCATE 清空后
TRUNCATE TABLE users;
INSERT INTO users (username, email, age) VALUES ('新用户', 'new@example.com', 20);
-- 新行 id = 1(重新开始)
外键约束
如果 orders 表有外键引用 users 表,对 users 表执行 TRUNCATE 会被拒绝:
ERROR 1701: Cannot truncate a table referenced in a foreign key constraint
这时候只能用 DELETE,或者先临时关闭外键检查(后面约束章节会讲)。
18.5 ON DELETE CASCADE:级联删除
建外键时可以指定 ON DELETE CASCADE,意思是”主表行被删时,自动删掉从表中关联的行”。
假设 orders 表的外键定义如下:
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
amount DECIMAL(10, 2),
status VARCHAR(20),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB;
加了 ON DELETE CASCADE 后,删 users 表的某个用户时,orders 表里该用户的所有订单会自动删除:
-- 删用户 id=3
DELETE FROM users WHERE id = 3;
-- orders 表中 user_id=3 的行也会自动被删掉
Note级联删除很方便,但也有风险。删一个用户可能连锁删掉大量关联数据,有时这不是你想要的。如果只想保留订单但断开关联,用
ON DELETE SET NULL(把外键设为 NULL)更合适。外键策略的选择在约束章节会详细讲。
18.6 删除操作的常见陷阱
删了数据但空间没释放
InnoDB 存储引擎下,DELETE 删掉数据后,磁盘空间不会立即还给操作系统。数据页被标记为可复用,但文件大小不变。想要真正回收空间,可以执行:
OPTIMIZE TABLE orders;
但这会锁表一段时间,生产环境慎用。
删数据 vs 删表
别混淆 DELETE 和 DROP:
DELETE FROM 表名— 删数据,表还在DROP TABLE 表名— 表结构和数据一起删,表没了
-- 只清空数据,表结构保留
DELETE FROM orders;
-- 连表带数据一起删
DROP TABLE orders;
软删除 vs 硬删除
实际开发中,很多场景不用真的 DELETE,而是”软删除”—加一个 deleted_at 列标记删除时间:
-- 软删除:标记为已删除
UPDATE users
SET deleted_at = NOW()
WHERE id = 5;
-- 查询时排除已删除的
SELECT * FROM users
WHERE deleted_at IS NULL;
软删除的好处是数据可以恢复,还能做审计追踪。代价是查询时总得记得加 WHERE deleted_at IS NULL。
Tip关键业务数据(用户、订单)建议软删除。日志、临时数据可以硬删除。根据业务场景选择,别一刀切。
18.7 小结
删除数据有三个工具:DELETE 按条件删、DELETE JOIN 跨表删、TRUNCATE 清空整表。记住 DELETE 可回滚可加条件但慢,TRUNCATE 快但不可回滚不可加条件。外键级联删除(ON DELETE CASCADE)能自动处理关联数据,但要谨慎使用。不管用哪种方式,删之前先 SELECT 确认,删之后有备份兜底。下一章开始进入查询主题,先从最基础的 SELECT 学起。