UNION ALL 比 UNION 快得多,100万行时耗时仅810ms vs 9200ms(相差11倍以上),因UNION需临时表、排序去重,而UNION ALL无此开销。

UNION ALL 比 UNION 快多少?看数据量就明白
直接说结论:UNION ALL 在绝大多数场景下都该优先选,尤其当数据量超过几万行时,UNION 的性能代价会急剧放大。这不是“建议”,而是执行计划层面的硬差异。
MySQL 8.0 下实测:100 万行合并时,UNION 耗时 9200ms,UNION ALL 仅 810ms——相差 11 倍以上。瓶颈不在网络或磁盘,而在数据库必须为 UNION 创建临时表、触发 Using temporary 和 Using filesort,排序去重本身是 O(n log n) 复杂度。
- 如果你的子查询结果天然无重复(比如按时间分表的日志),
UNION的去重纯属浪费资源 - 如果后续还要加
WHERE或ORDER BY,那UNION先排序再筛选,更是双重低效 - 注意:某些旧版 MySQL(如 5.6)对
UNION ALL的索引下推支持更友好,而UNION可能直接放弃部分优化
什么时候非用 UNION 不可?别靠猜,看语义
UNION 不是“更安全”的默认选项,它是有明确语义责任的:你必须需要「逻辑上唯一的结果集」。
典型刚性需求场景:
- 合并客户主数据(CRM + ERP + 线下登记表),ID 或手机号可能交叉录入,重复即脏数据
- 统计口径归并,例如
SELECT 'daily', COUNT(*) FROM logs WHERE dt='2026-03-14' UNION SELECT 'weekly', COUNT(*) FROM logs WHERE week='2026-W11'—— 这里两行标签不同,但若某天同时命中两个条件,UNION才能防重复计数 - ETL 清洗阶段最后一道去重,且无法在上游保证唯一性
反例:用 UNION 合并 user_db1.users 和 user_db2.users,只因“怕重复”——但如果业务约定 user_id 全局唯一,这就是用错工具。
列对齐和 NULL 处理:容易被忽略的隐性坑
两者都要求各 SELECT 的列数、顺序、类型兼容,但 UNION 对 NULL 更“敏感”:多个 NULL 值会被视为相同并去重;而 UNION ALL 保留所有 NULL 行。
常见翻车点:
- 字段名不一致导致结果列标题混乱:
SELECT id, name FROM t1 UNION ALL SELECT uid, full_name FROM t2→ 实际返回列名是第一个SELECT的id和name,第二个的uid/full_name被丢弃 - 类型隐式转换失败:
SELECT 1 UNION SELECT '1'在严格模式下报错,而UNION ALL同样报错——别以为ALL就能绕过类型检查 - 排序行为差异:
UNION默认按第一列升序排(MySQL 行为),UNION ALL完全不排序,依赖子查询自然顺序;若需稳定顺序,外层必须显式加ORDER BY
CTE 和子查询里怎么选?看中间结果是否可信
在 WITH 子句中构建中间集合时,选择取决于你对中间数据的控制力。
推荐做法:
- 用
UNION ALL拼接原始分片表(如sales_2025_q1,sales_2025_q2),再在外层统一WHERE过滤和GROUP BY—— 避免每个分片都做去重 - 若中间结果已通过
DISTINCT或唯一索引约束确保无重复,则后续用UNION ALL是最干净的 - 慎用
UNION嵌套:比如(SELECT ... UNION SELECT ...) UNION (SELECT ...),每层都触发独立去重,开销叠加
真正难的是判断“是否已有重复”——不要假设,查 COUNT(*) 和 COUNT(DISTINCT key) 对比一下,比凭经验靠谱。











