UNION ALL 与 UNION 仅差 ALL 关键字,但前者跳过去重排序、后者隐式 DISTINCT 并默认排序;二者均要求列数一致、类型兼容、顺序对齐,且 ORDER BY/LIMIT 必须置于末尾作用于整体结果。

UNION ALL 和 UNION 的语法差异只在关键字本身
语法上,UNION ALL 和 UNION 唯一区别就是多了一个 ALL 关键字——它不改变 SELECT 结构、不新增括号、不调整列顺序,也不影响 WHERE 或 JOIN 的写法。
但这个“小改动”直接决定了 MySQL 怎么处理重复行和执行计划:
-
UNION会隐式加DISTINCT+ 默认按第一列排序(除非显式禁用) -
UNION ALL完全跳过去重和排序步骤,只是把两个结果集物理拼接 - 两者都要求:每个
SELECT的列数必须一致,对应列类型需兼容(如INT和BIGINT可隐式转换,但DATE和VARCHAR不行,得用CAST)
列名、类型、顺序这三项必须对齐,否则直接报错
MySQL 合并时不会帮你“猜意图”,而是严格校验结构。常见报错 Error 1222: The used SELECT statements have a different number of columns 就是列数不一致。
实操建议:
- 列名取自第一个
SELECT的别名(比如SELECT name AS title FROM a UNION SELECT username FROM b,结果列名是title) - 类型不匹配时,宁可显式
CAST也不要依赖隐式转换(例如SELECT CAST(created_at AS CHAR) FROM orders UNION ALL SELECT update_time FROM logs) - 如果表字段顺序不同(如
users(id, name)vsadmins(name, id)),必须手动调整 SELECT 列序:SELECT id, name FROM users UNION ALL SELECT id, name FROM admins
ORDER BY 和 LIMIT 必须放在最后,且只能作用于整个结果集
你不能在每个子查询里单独写 ORDER BY 来控制合并顺序——MySQL 会忽略它(除非配合 LIMIT,但仍有风险)。
正确写法只有一种结构:
SELECT id, name FROM table1 UNION ALL SELECT id, name FROM table2 ORDER BY id DESC LIMIT 20;
错误写法(会报语法错误或行为不可控):
(SELECT id, name FROM table1 ORDER BY id) UNION ALL (SELECT id, name FROM table2 ORDER BY id);
注意:ORDER BY 在 UNION / UNION ALL 中不是可选修饰,而是顶层指令,它对整个合并后结果生效。
什么时候必须用 UNION,什么时候该死守 UNION ALL
别凭感觉选。关键看数据语义和性能预期:
- 用
UNION:跨业务系统拉取「用户列表」,怕同一人出现在多个源表中;报表去重统计唯一设备 ID - 用
UNION ALL:日志表(log_202512+log_202601)合并查错误;过程表和归档表联合分页(确认无主键重叠) - 性能陷阱:即使你加了
WHERE过滤,UNION仍要对最终结果做全局去重,大结果集下 I/O 和临时表开销陡增 - 安全提示:如果用了
UNION却没检查是否真有重复数据,可能掩盖数据质量问题(比如双写导致同一条订单进了两张表)
最常被忽略的一点:UNION 的“去重”是全字段比对,不是按主键。哪怕两行只有时间戳差 1 秒,也会算作不同行——所以别指望它替你 dedupe 业务逻辑意义上的重复。










