UNION去重且隐式排序,UNION ALL不去重不排序;前者性能低但结果唯一,后者性能高但保留重复,选择取决于业务是否需去重及对执行效率的要求。

UNION 和 UNION ALL 的核心区别就两点:是否去重、是否隐式排序。选哪个不看“习惯”,只看你的数据要不要唯一、查得快不快。
UNION 会自动去重 + 隐式排序,但代价是性能下降
当你写 SELECT a FROM t1 UNION SELECT a FROM t2,数据库实际干了三件事:合并结果 → 去重(类似加了 DISTINCT)→ 按字段默认规则排序(多数引擎按第一列升序)。这在小表上不明显,但一旦子查询返回几万行,UNION 很可能触发临时磁盘排序和哈希去重,CPU 和 I/O 开销陡增。
- 常见错误现象:
UNION查询比单个SELECT慢好几倍,执行计划里出现Using temporary; Using filesort - 如果你的两个子查询本身就没重复(比如查不同状态的订单:
status = 1和status = 2),那UNION的去重纯属浪费 - 注意:即使你显式写了
ORDER BY,UNION仍会在去重后额外做一次排序,除非用括号明确包裹整个UNION并在外层再ORDER BY
UNION ALL 不去重、不排序,性能通常高 20%~50%
UNION ALL 就是简单拼接,把第一个结果集所有行、第二个结果集所有行依次追加,不做任何比较或重排。这意味着:
- 它不会帮你发现逻辑错误——比如两个子查询本该互斥,却因条件写错导致重复,
UNION ALL会原样暴露出来 - 结果顺序完全由子查询执行顺序决定;如果需要稳定顺序,必须每个子查询都带
ORDER BY,且最终外层再套一层ORDER BY - 某些场景下反而更安全:比如合并日志表(
log_202604和log_202605),天然无交集,用UNION ALL避免误删有效重复记录
列数、类型、顺序必须严格一致,否则报错
不管用 UNION 还是 UNION ALL,以下三点任一不满足都会直接报错,不是警告:
- 每个
SELECT的列数必须相等(SELECT id, name和SELECT id不行) - 对应位置的列类型需兼容(
VARCHAR(50)和TEXT通常可隐式转换,但INT和JSON不行) - 列名以第一个
SELECT为准,后续子查询的别名无效(SELECT a AS x FROM t1 UNION SELECT b AS y FROM t2,结果列名仍是x)
真实业务中怎么选:先问自己三个问题
别背规则,现场判断:
- 这两个结果集在业务语义上会不会有重复?比如查「已支付订单」和「已发货订单」,状态有重叠,必须用
UNION;查「2026年4月订单」和「2026年5月订单」,时间不重,用UNION ALL - 下游应用是否依赖结果唯一?比如填充下拉框,重复项会导致前端异常,宁可慢一点也用
UNION - 有没有其他方式保证唯一?比如两个子查询都加了
WHERE type IN (1,2)和WHERE type IN (3,4),值域无交,那UNION ALL更合适
最容易被忽略的一点:很多开发者看到「去重」就条件反射选 UNION,但没意识到——如果重复是脏数据导致的,掩盖它不如定位并修复源头逻辑。

















