优先使用 union all,它更快、更可控、更少出错;需严格对齐列数、顺序、类型,首条 select 决定结构,错误类型组合易报错,排序分页只能置于最后。

优先用 UNION ALL,只要你不依赖去重,它就是更快、更可控、更少出错的选择。
列数和字段顺序必须严格对齐
MySQL 不会按字段名匹配,只看位置。第一个 SELECT 的列结构就是模板,后面所有 SELECT 都得照着排。
- 错误写法:
SELECT id, name FROM users UNION ALL SELECT created_at, status FROM logs—— 列顺序错,类型错,直接报错或数据错位 - 正确写法:统一为
id,name,source三列,缺的用NULL或默认值占位:SELECT id, name, 'users' AS source FROM users UNION ALL SELECT id, NULL AS name, 'logs' AS source FROM logs - 别指望别名生效:第二个
SELECT里写id AS order_id没用,最终列名还是第一个里的id
数据类型兼容性比你想象中更敏感
MySQL 会尝试隐式转换,但边界很窄,一碰就崩。别赌它能“自动修好”。
- 安全组合:
INT和TINYINT、VARCHAR(20)和VARCHAR(100)、DECIMAL(10,2)和FLOAT - 高危组合:
TINYINT和DATETIME、CHAR(1)和JSON、BIT(1)和BOOLEAN(后者实际是TINYINT,但语义冲突易误判) - 建议:显式转类型,比如用
CAST(created_at AS CHAR)强制对齐字符串列,比靠隐式转换更稳
排序和分页只能加在最后
UNION ALL 是集合操作,不是嵌套容器。中间加 ORDER BY 或 LIMIT 会语法报错,除非包成子查询。
- ❌ 错误:
SELECT * FROM t1 ORDER BY id LIMIT 5 UNION ALL SELECT * FROM t2 - ✅ 正确(取每边最新 5 条再合并):
(SELECT * FROM t1 ORDER BY id DESC LIMIT 5) UNION ALL (SELECT * FROM t2 ORDER BY id DESC LIMIT 5) - ✅ 整体排序分页:
SELECT ... UNION ALL SELECT ... ORDER BY 1 DESC LIMIT 20(注意ORDER BY 1指第一列,不是列名)
为什么 UNION ALL 更快,以及它快在哪
快在跳过了三步开销:排序、哈希去重、临时表落盘。尤其当结果集大时,这三步可能让 UNION 直接卡住或 OOM。
-
UNION ALL就是内存里把几块结果 buffer 顺序拼起来,IO 和 CPU 开销都最小 -
UNION会触发Using temporary; Using filesort,EXPLAIN 里一眼可见 - 真实场景下,如果你合并的是不同日期分区表、不同业务线用户表、或带明确来源标识的数据,根本不需要去重 —— 这时候还用
UNION纯属自找麻烦
最容易被忽略的一点:字段对齐不是“看着差不多就行”,而是“每个位置的值在语义和类型上都可互换”。宁可多写几个 NULL 或 CAST,也别信 MySQL 的自动兜底。一旦类型强转失败,整条 UNION ALL 就会中断返回错误,而不是静默出错。











