首页/数据/SQL 速查/UNION 与 UNION ALL 的成本差异
性能与执行计划72 条

UNION 与 UNION ALL 的成本差异

UNION 默认去重:需要临时表或排序去重;UNION ALL 直接拼接,配合外层排序与 LIMIT 更省。

SQL 速查数据更新于 2026-10-13

两种合并的成本差异

UNION 默认去重:两段结果先合并再按整行去重,多数实现要走临时表或排序,代价随结果集增大而上升。UNION ALL 直接拼接、不去重,省掉这一步。选哪个取决于业务是否真的需要去重,很多场景里数据本来就不会重复。

基本信息

UNION 语义合并后去重,等价于加了 DISTINCT
UNION ALL 语义直接拼接,保留重复行
去重代价临时表或排序,结果集大时显著
分支执行每个分支独立使用各自的索引与过滤条件
外层排序ORDER BY 与 LIMIT 作用于合并后的最终结果

典型使用场景

  • 合并多张按年份分表的历史表做统计
  • 把不同条件的查询结果拼成一张报表
  • 各分支先取 Top N,再合并取全局 Top N
  • 多来源数据统一分页或导出
  • 把明细与汇总行并到同一个结果集里

示例

示例
-- 有重复可能、业务确实需要去重时才用 UNION
SELECT id FROM orders_2023
UNION
SELECT id FROM orders_2024;

-- 语义上不会重复时用 UNION ALL:省去去重那一步
SELECT id FROM orders_2023
UNION ALL
SELECT id FROM orders_2024;

-- 分支各自取 Top N,外层统一排序取全局 Top N
(SELECT id, created_at FROM orders_2023 ORDER BY created_at DESC LIMIT 10)
UNION ALL
(SELECT id, created_at FROM orders_2024 ORDER BY created_at DESC LIMIT 10)
ORDER BY created_at DESC LIMIT 10;

两种写法对照

维度UNIONUNION ALL
去重会去重不去重
执行代价需要临时表或排序去重只需拼接,代价低
结果行数不超过两段行数之和等于两段行数之和
适用场景业务确实需要去重数据源之间没有重复交集
分支 LIMIT需要括号包裹才生效同样需要括号
各分支的列个数、顺序与类型必须一致,结果列名取自第一个分支。类型不一致时会按类型优先级做隐式转换,可能带来意料外的比较与排序结果。
外层 ORDER BY 作用于合并后的全部行。想先在每个分支里限制行数,必须用括号包住分支,否则 LIMIT 的语义会变成对最终结果生效。

易错点

  • 习惯性写 UNION:结果集大时去重成本很高,业务本来不会重复也白付代价,先确认是否真的需要去重
  • 想给分支加 LIMIT 却放错位置:MySQL 需要括号包裹分支,否则 LIMIT 作用在最终结果上,行数与预期不同
  • 分支的列顺序或类型不一致:隐式转换会让比较与排序结果反常,甚至丢掉精度
  • 用 UNION 去重后发现数据还在:去重按整行比较,两分支其他列不同就不算重复
  • 大结果集 UNION 后再 ORDER BY 加 LIMIT:去重与排序各付一次代价,可先在分支里缩小范围

数据来源与参考

  • MySQL 8.0 Reference Manual · UNION
  • PostgreSQL Documentation · UNION
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌