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