UNION ALL 与 UNION 仅差 ALL 关键字,但前者跳过去重排序、后者隐式 DISTINCT 并默认排序;二者均要求列数一致、类型兼容、顺序对齐,且 ORDER BY/LIMIT 必须置于末尾作用于整体结果。
语法上,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) vs admins(name, id)),必须手动调整 SELECT 列序:SELECT id, name FROM users UNION ALL SELECT id, name FROM admins
你不能在每个子查询里单独写 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:跨业务系统拉取「用户列表」,怕同一人出现在多个源表中;报表去重统计唯一设备 IDUNION ALL:日志表(log_202512 + log_202601)合并查错误;过程表和归档表联合分页(确认无主键重叠)WHERE 过滤,UNION 仍要对最终结果做全局去重,大结果集下 I/O 和临时表开销陡增UNION 却没检查是否真有重复数据,可能掩盖数据质量问题(比如双写导致同一条订单进了两张表)最常被忽略的一点:UNION 的“去重”是全字段比对,不是按主键。哪怕两行只有时间戳差 1 秒,也会算作不同行——所以别指望它替你 dedupe 业务逻辑意义上的重复。