先说几个核心判断:UNION ALL 比 UNION 快,根本原因不是“少做了一个去重操作”,而是它直接跳过了整个去重+排序的数据处理链路——数据库压根不会启动那套机制。换句话说,一个是走完全流程,一个是抄近道直达,结果自然是天壤之别。 100 万行级别的数据量,慢 11 倍只是起步价。如果嵌套在视
SQL视图UNION ALL效率高于UNION的原因
作者:技术拾光
时间:2026-06-17
浏览:305
文章目录
先说几个核心判断:UNION ALL 比 UNION 快,根本原因不是“少做了一个去重操作”,而是它直接跳过了整个去重+排序的数据处理链路——数据库压根不会启动那套机制。换句话说,一个是走完全流程,一个是抄近道直达,结果自然是天壤之别。
100 万行级别的数据量,慢 11 倍只是起步价。如果嵌套在视图里再套一层 LIMIT OFFSET,这个代价翻倍都不止。更关键的是,很多人并不清楚这种性能衰减到底从何而来。
UNION 实际触发的是 DISTINCT + ORDER BY 两层开销
UNION不是简单的“先合并再筛选”,而是后台悄悄搞了一套集合归并流程:所有子查询的结果必须先写入临时结构(内存或者磁盘),然后做哈希或排序去重,最后再默认按第一列升序输出——即便你没写ORDER BY,它也会这么干。- 看执行计划你会发现,
Using temporary和Using filesort是常客。尤其当参与列没有索引、数据量超过 5 万行时,I/O 和 CPU 的压力会迅速成为瓶颈。 - 更有意思的是,就算你在外层加了
ORDER BY id,数据库也有可能执行两次排序:一次是为了去重,一次是为了你显式指定的顺序。这个“隐性双倍开销”,才是容易被忽视的坑。
UNION ALL 的玩法完全不同——纯流式拼接,零中间态
- 它不做任何行级比较,不申请额外内存建哈希表,不写临时文件,也不调整顺序。第一个
SELECT开始返回数据,第二个紧接着追加,全程保持 pipeline 模式。从执行计划的EXPLAIN输出就能一眼看出来:干干净净,没有任何Using temporary或Using filesort。 - 对于分表查询(比如
log_202604和log_202605)、状态互斥查询(比如status = 1和status = 2),UNION ALL不仅在语义上更准确,性能表现也更可预期——不会因为数据量的波动而突然变慢。
别被“宽容”的假象迷惑——列对齐和类型兼容性要求完全一致
UNION ALL并不比UNION更“好说话”:列数不等、类型不兼容(例如INT和JSON)、NULL 性约束冲突(NOT NULL 与 NULLable),它一样会报错。别指望用UNION ALL来绕过类型检查。- 一个典型的例子:MySQL 8.0+ 在严格模式下,如果第一条
SELECT返回的是NOT NULL VARCHAR(50),第二条返回NULL,它直接拒绝执行,不给任何通融余地。 - 列名永远以第一个
SELECT为准——后续子查询里的别名(比如SELECT id AS uid)是无效的。这个规则在很多真实场景中引发过令人困惑的 bug。
外层 ORDER BY 才是唯一可控的排序方式
- 子查询里写
ORDER BY基本是白费功夫——语法允许,但实际被忽略。UNION的隐式排序规则不可靠(可能按主键,也可能按表达式推导出的列),UNION ALL更是完全依赖执行顺序。 - 正确的写法只有一种:
SELECT id, name FROM users_2023 UNION ALL SELECT id, name FROM users_2024 ORDER BY id;
- 少了这句
ORDER BY,结果顺序在不同 MySQL 版本、不同执行路径下都可能变化。上线后一旦前端渲染错乱或者分页错位,排查起来相当费力——因为问题不是每次都出现,而是随机性的。
说到底,UNION 的性能衰减是非线性的。100 万行时慢 11 倍,嵌套在视图里再加一层 LIMIT OFFSET,代价可能翻倍还不止。真正值得关注的不是“多用 UNION ALL 还是 UNION”这个选择题,而是理解数据库底层到底做了什么、跳过了什么、以及这些差异在日常开发中会怎样累积成性能的压倒性差距。
实用工具推荐
电子包浆
使用 ›绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
图片压缩
使用 ›选择画质和输出格式,预览压缩前后的大小。