UNION ALL 是 MySQL 中最高效的结果集合并方式,需严格对齐列数与顺序、确保类型兼容,并仅在末尾使用 ORDER BY 和 LIMIT;它适用于分表合并等场景,而非替代 JOIN。

UNION ALL 是 MySQL 中最高效的结果集合并方式,只要你不依赖自动去重,就该默认选它。
列数和字段顺序必须严格对齐
每个 SELECT 的列数量、位置顺序必须完全一致。MySQL 不会按字段名匹配,只看位置。
- 第一个
SELECT是模板:它的列名决定最终结果集的字段名,后续所有SELECT的别名都会被忽略 - 如果某张表缺字段,用
NULL或默认值占位,例如:SELECT id, name, NULL AS city FROM t1 - 反例:写成
SELECT name, id FROM t1 UNION ALL SELECT id, name FROM t2→ 数据会错位(name 值跑到 id 列里)
对应列的数据类型要兼容
MySQL 会尝试隐式转换,但不可靠。类型不兼容时可能报错,或返回意外值(比如 TINYINT 和 DATETIME 强行合并)。
- 安全组合:
INT/BIGINT、VARCHAR(10)/VARCHAR(100)、DECIMAL/INT - 危险组合:
CHAR和DATE、BIT和TEXT、不同精度的浮点类型混用 - 建议显式转换,比如:
CAST(created_at AS DATE)统一时间字段类型
排序和分页只能加在最后
UNION ALL 是集合操作,不是嵌套结构。中间每个 SELECT 单独加 ORDER BY 或 LIMIT 会报错,除非用括号包成子查询。
- 整体排序:写在末尾,如
UNION ALL SELECT ... ORDER BY created_at DESC - 限制总条数:也放最后,如
UNION ALL SELECT ... LIMIT 50 - 若某一边只想取最新 5 条,必须先子查询:
(SELECT * FROM logs WHERE type='error' ORDER BY id DESC LIMIT 5) UNION ALL ...
别把 UNION ALL 当 JOIN 用
它只是纵向拼接,不建立行间关联。想按主键/条件关联数据,该用 JOIN 就用 JOIN;想合并明细、统计分渠道来源、拼接历史分区表,才是 UNION ALL 的主场。
- 典型误用:用
UNION ALL拼两个有逻辑关系的表(比如订单 + 订单详情),结果是字段错位、语义混乱 - 典型正用:合并
orders_2024、orders_2025两张按年分表;拼接线上用户表和线下导入用户表 - 性能陷阱:大表合并时,
UNION会触发临时表 + 排序,而UNION ALL只需顺序读取和追加 —— 这个差异在千万级数据上就是秒级与分钟级的区别
字段对齐、类型兼容、末尾控制排序分页——这三点漏掉任意一个,都可能让结果错得悄无声息。尤其当字段名相似但语义不同(比如两个表都有 status,一个是订单状态,一个是用户激活状态),光看 SQL 很难发现问题。


















