适用读者:分不清
delete/truncate/drop的人。
前置:S11-B02。
实测环境:MySQL 8.0.46(s11lab,20,000 行,2026-11-05)。
覆盖旧文:1219(39) 1220(73) 1215(45) 1211(29) 1232(25) 846(98) 2593(326) 1729(101) 1750(112) 352(74) 1216(61) 1217(37) = 1,020 点。
覆盖扩展:E-S11-012(ALTER的代价)。
上一篇:S11-B03 · 查询:WHERE / JOIN / GROUP BY / 子查询 / 分页
下一篇:S11-B05 · 索引基础。
1. 一句话结论
三个"删除"的差别不在"删多少行",在"能不能回滚、要不要重建、自增要不要重置"。
| 命令 | 删什么 | 可回滚 | 自增重置 | 实测耗时(2 万行) |
|---|---|---|---|---|
delete |
行(逐行 + undo) | ✅ | ❌(继续累加) | 848 ms |
truncate |
重建表 | ❌ | ✅ | 293 ms |
drop |
表结构 + 数据 | ❌ | — | 极快 |
实测(2 万行):delete 848 ms vs truncate 293 ms(2.9×)。
2. 实测:自增主键的差异
insert into t_seq(v) values(1),(2),(3); -- id = 1,2,3
delete from t_seq; -- 全删
insert into t_seq(v) values(9);
实测:
delete 后插入 → id = 4 ← 继续累加
truncate 后插入 → id = 1 ← 重置
这条差异解释了一个常见现象:"为什么自增主键不连续"(A-2404,A01 §3 详讲)——delete/回滚/批量插入失败都会留下空洞。
3. delete 为什么慢
| 原因 | 说明 |
|---|---|
| 逐行删除 | 每行都要标记删除位 + 写 undo |
| 产生大量 undo/redo | 大事务还会撑爆 undo 表空间 |
| 触发器 | delete 会触发 DELETE 触发器 |
判据:"要清空整表吗?" 要 → truncate(快且重置自增);要条件删除 → delete(但必须分批,否则大事务)。
分批删除的标准写法:
delete from t where created_at < '2025-01-01' limit 1000; -- 循环执行
4. ALTER 的代价(E-S11-012)
| 操作 | 代价 |
|---|---|
| 加列(末尾) | 8.0 起多为 INSTANT(很快) |
| 加索引 | 需扫描建索引(Online DDL 可并发读) |
| 改列类型 | 可能重建表(COPY) |
| 改字符集 | 重建表 |
判据:"这个 DDL 会不会锁表?" 会 → 用 pt-online-schema-change/gh-ost(A-1216 的实践延伸)。
5. 打印 SQL 与开发体验(A-352)
P6Spy 能打印"真实执行的 SQL + 耗时"(含参数已替换):
| 环境 | 是否启用 |
|---|---|
| 本地开发 | ✅ 强烈推荐(看清实际 SQL) |
| 生产 | ❌ 禁用(性能与信息泄露) |
这条与 S08-B04 的 log-impl=StdOutImpl 同源:能看到真实 SQL 是排障的前提。
6. 五个误区
| 误区 | 真相 |
|---|---|
"delete 能重置自增" |
不能,truncate 才能 |
"truncate 可以回滚" |
不能(DDL 语义) |
"delete 全表更快" |
比 truncate 慢(实测 2.9×) |
| "加索引不锁表" | Online DDL 也有短暂锁 |
| "改列类型很轻" | 常需重建表 |
7. 自检
- 三个删除命令的四个维度差异?
- 实测里
delete与truncate差几倍? delete后自增值会怎样?truncate呢?- 大表条件删除该怎么做?
- 哪些
ALTER会重建表?
8. 下一篇
S11-B05 · 索引基础:类型、结构与最左前缀
写入讲完,下一篇讲读快的核心:索引为什么是 B+ 树、聚簇与二级索引的区别、最左前缀。
本篇属于系列《S11 · 数据库与 SQL》。旧文来源:A-1219/1220/1215/1211/1232/846/2593/1729/1750/352/1216/1217;扩展点 E-S11-012。耗时与自增行为为 MySQL 8.0.46 实测。