UNION ALL 效率远高于 UNION,因其不排序、不去重、不建临时表;UNION 等价于 UNION ALL 加 DISTINCT 和隐式 ORDER BY,强制使用临时表和文件排序,I/O 与 CPU 开销随数据量非线性激增。

UNION ALL 效率更高,因为它不做去重、不排序、不建临时结构;UNION 实际等价于 UNION ALL + DISTINCT + 隐式 ORDER BY,强制触发临时表和文件排序,I/O 和 CPU 开销随数据量非线性陡增。
UNION 实际执行的是 DISTINCT + ORDER BY
你以为 UNION 只是“去掉重复行”,其实数据库(尤其是 MySQL 8.0+)内部把它重写为:SELECT DISTINCT * FROM (subquery1 UNION ALL subquery2) ORDER BY ...。哪怕你没写 ORDER BY,去重过程本身也依赖排序或哈希,必须把全部结果先拉进临时结构。
- EXPLAIN 里必见
Using temporary和Using filesort - tmp_table_size 不够时,临时表直接落盘成 MyISAM 表,I/O 成瓶颈
- 即使两表天然无交集(如
log_202601和log_202602),这套流程照常执行
UNION ALL 是纯流式拼接,零中间开销
UNION ALL 就是字面意思:子查询 A 输出第一行,立刻发给客户端;A 结束,B 紧接着输出——不缓存、不比较、不建哈希表、不申请排序缓冲区。
- EXPLAIN 干净,看不到
Using temporary或Using filesort - 100 万行实测:UNION ALL ≈ 810ms,UNION ≈ 9200ms(慢 11 倍以上)
- 性能差距不是常数倍,而是随数据量指数级加重——去重排序本身是
O(n log n),叠加磁盘交换更致命
列对齐、类型兼容、NULL 处理,两者要求完全一致
别以为换 UNION ALL 就能绕过结构校验。只要出错,报错信息和 UNION 一模一样:
- 列数不等 → 直接报
ERROR 1222 - 对应列类型不兼容(如第一条返回
NOT NULL VARCHAR(50),第二条返回NULL)→ 严格模式下直接失败 -
NULL在UNION中被视为相等并去重,在UNION ALL中保留全部——这可能暴露你没意识到的空值分布问题 - 列名永远以第一个
SELECT为准,后续子句的AS别名无效
ORDER BY 必须写在外层,子查询里的写法无效
下面这种写法是错的,MySQL 会忽略两个子查询里的 ORDER BY:
SELECT id FROM t1 ORDER BY create_time DESC UNION ALL SELECT id FROM t2 ORDER BY create_time DESC;
正确方式只有一种:
SELECT id FROM t1 UNION ALL SELECT id FROM t2 ORDER BY id;
但要注意:一旦加了外层 ORDER BY,UNION ALL 也会触发排序,性能优势就打折扣了。真正可控的方式是——靠子查询自身索引保证局部有序,再用外层 ORDER BY 最小化排序范围。
最容易被忽略的是:UNION 的性能衰减由底层机制决定,无法靠调优参数绕过;是否用它,只取决于业务是否真需要去重——如果只是图省事默认选 UNION,等于主动给自己埋雷。

















