UNION ALL在视图中性能更好,因其跳过去重和隐式排序;UNION等价于UNION ALL加DISTINCT和ORDER BY,必触发临时表与文件排序,导致I/O瓶颈和执行计划臃肿。

UNION ALL 在视图中性能更好,是因为它跳过了去重和隐式排序这两步开销极大的操作;而 UNION 实际等价于先 UNION ALL 再套一层 DISTINCT + ORDER BY,必然触发临时表和文件排序。
UNION 在视图里会强制走临时表和 filesort
你在视图定义里写 SELECT * FROM t1 UNION SELECT * FROM t2,数据库不会“聪明地”只去重有交集的行——它必须把两个子查询的全部结果先拉到内存(或磁盘)临时表里,再做哈希去重 + 全局排序。EXPLAIN 里一眼就能看到 Using temporary 和 Using filesort。哪怕你后续查这个视图时加了 LIMIT 10,优化器也大概率无法下推,因为去重排序是前置强依赖。
- 临时表一旦撑爆内存(比如
tmp_table_size不够),立刻写磁盘,I/O 成瓶颈 - 即使两表天然无交集(如按时间分片的
orders_2023和orders_2024),UNION 仍照常执行全套流程 - 视图被多次引用时(比如嵌套在另一个视图或报表 SQL 中),这套开销会被重复放大
UNION ALL 是纯流式拼接,零中间结构
UNION ALL 的行为就是字面意思:第一个子查询开始输出,数据就往客户端/上层查询流过去;刚输完,第二个子查询紧跟着接上。没有哈希表、没有排序缓冲区、不申请额外内存做比较。
- EXPLAIN 看不到
Using temporary或Using filesort,执行计划干净 - 大数据量下优势陡增:100 万行时,UNION ALL 耗时约 810ms,UNION 可达 9200ms(11 倍以上)
- 但注意:它不保证顺序——如果你依赖「t1 数据全在前、t2 全在后」,得靠子查询自身加
ORDER BY,且外层还得再套一次ORDER BY才可靠
列对齐和类型检查,UNION 和 UNION ALL 一视同仁
别以为换用 UNION ALL 就能绕过结构校验。只要列数不等、对应列类型不兼容(比如第一条返回 NOT NULL VARCHAR(50),第二条返回 NULL),MySQL 8.0+ 会直接报错,和用不用 UNION 无关。
- 列名永远以第一个
SELECT为准,后面子查询的AS别名无效 - 隐式转换失败很常见:比如
INT和VARCHAR混用,在严格模式下直接拒绝,不是“慢”,而是根本跑不起来 - NULL 值处理有差异:多个
NULL在UNION中被视为相同并去重,UNION ALL保留全部——这可能暴露你没意识到的数据空值分布问题
视图里用 UNION 的唯一合理场景极少
除非你能确认:业务语义上两路数据确实存在不可控交集,且下游系统强依赖“结果唯一”(比如填充前端下拉框、生成唯一 ID 列表),否则在视图里用 UNION 几乎总是错的。
- 更稳妥的做法是:视图用
UNION ALL保证性能,去重逻辑交给上层应用或 CTE 显式控制(SELECT DISTINCT ... FROM (your_view) v) - 如果真要用
UNION,务必在外层显式加ORDER BY——子查询里的ORDER BY会被忽略,而UNION的隐式排序规则(通常按第一列升序)很可能和你预期不符 - 最容易被忽略的是分页场景:
SELECT * FROM your_union_view LIMIT 10 OFFSET 1000,UNION 的全局去重会让 offset 前 1000 行也参与计算,成本远超必要
真正卡住性能的,往往不是语法本身,而是你以为“去重很轻量”,却没意识到数据库为此要建临时表、排序、甚至刷盘——这些动作在视图定义里是静默发生的,直到某天数据量翻倍、报表超时告警响起,才突然暴露。


















