union默认去重并隐式排序,代价是临时表和sort运算;union all仅叠加无去重,性能更高。二者列数、类型、顺序要求完全一致,需显式转换确保兼容性。

UNION 去重是默认行为,但代价是排序和临时表
UNION 本质不是“合并”,而是“合并 + 去重 + 排序”。数据库执行 UNION 时,会把两个结果集先拼起来,再用类似 DISTINCT 的逻辑逐行比对、去重,最后还会按字段顺序隐式排序(除非显式加 ORDER BY)。这意味着:即使你只查两列整数,只要数据量上万,就可能触发磁盘临时表和额外的 Sort 运算。
- 常见错误现象:
UNION查询变慢、执行计划里出现Sort或Hash Match (Aggregate) - 使用场景:真正需要唯一结果,比如“用户表 + 备份用户表”中取所有不重复手机号
- 性能影响:在 SQL Server 或 MySQL 中,
UNION比UNION ALL多 20%–200% 执行时间,取决于重复率和数据量
UNION ALL 不去重、不排序,快是它唯一的强项
UNION ALL 就是纯叠加——把第一个 SELECT 的所有行、原样不动地接上第二个 SELECT 的所有行,不做任何比较、不建临时结构、也不调整顺序。所以它快,且确定性强。
- 常见错误现象:误用
UNION ALL导致报表里出现双倍订单、重复统计 - 使用场景:日志归档合并(如
log_202512和log_202601)、ETL 中已知无重叠主键的分表查询 - 参数差异:两个
SELECT的列数、类型兼容性、顺序要求,UNION ALL和UNION完全一致,别以为能松懈
列名、数据类型、NULL 处理这些细节一错就报错
无论用哪个,SQL 引擎都严格校验结构一致性。第一个 SELECT 的列名会成为最终结果集的列名;如果第二条语句对应位置是 NULL 或类型隐式转换失败(比如第一条是 INT,第二条是 VARCHAR),就会直接报错。
- 容易踩的坑:
SELECT id, name FROM t1 UNION SELECT id, NULL FROM t2—— 看似没问题,但如果name是NOT NULL字段,某些版本 MySQL 会拒绝隐式转成可空类型 - 兼容性影响:SQL Server 对
TEXT/NTEXT列不支持UNION(但支持UNION ALL);PostgreSQL 要求所有字段必须可比较(JSON类型在旧版就不行) - 实操建议:统一用
CAST显式转类型,比如CAST(NULL AS VARCHAR(50)),别依赖自动推导
什么时候该选 UNION?别凭感觉,看这三点
选 UNION 不是因为“看起来更干净”,而是因为业务逻辑真需要去重。否则,就是用性能换心理安慰。
- 必须用
UNION:上游数据源不可控、存在天然重叠(例如多个爬虫任务抓同一类网页)、审计/合规要求结果绝对唯一 - 可以换成
UNION ALL:已通过WHERE条件隔离(如status = 'active'vsstatus = 'archived')、主键或组合键完全不交集、后续还要再GROUP BY统计 - 复杂点在于:有些场景表面无重,实际有逻辑重复(比如不同渠道注册的同一手机号),这时光靠
UNION ALL不够,得提前清洗或改用ROW_NUMBER() OVER (PARTITION BY ...)控制去重粒度










