UNION ALL 直接拼接结果集,不做去重和排序,速度快且逻辑清晰;要求各SELECT列数相同、字段顺序严格对齐、类型兼容,列名以首个SELECT为准,ORDER BY和LIMIT需整体包裹。

直接用 UNION ALL 就行,它不做去重、不排序、不额外扫描,就是把多个查询结果“原样拼起来”,速度快且逻辑清晰,适合大多数整合场景。
列数和字段顺序必须严格一致
每个 SELECT 的列数量要一样,位置也要对齐。比如第一个查的是 id, name, status,后面所有查询都得按这个顺序来,不能第二个写成 name, id, status,否则数据会错位。
- 某张表缺某个字段,就用
NULL AS city或'' AS city占位 - 别用
SELECT *—— 字段顺序一变就崩,显式写出字段名才可控 - 最终结果集的列名以第一个
SELECT为准,后续子句里的别名(如title AS name)只在该子句内有效,不影响最终列名
字段类型兼容性比你想象中更敏感
对应位置的字段类型最好相同。MySQL 会尝试隐式转换,但有风险:
-
INT和DECIMAL可以转,一般没问题 -
VARCHAR(10)和VARCHAR(100)能合并,MySQL 以最长为准 -
TINYINT和DATETIME强行UNION ALL很可能报错或返回异常值 -
TEXT和VARCHAR混用可能触发警告,尤其在严格模式下
ORDER BY 和 LIMIT 必须整体包装,不能直接加在末尾
UNION ALL 是集合操作,不是嵌套结构,中间每个 SELECT 不能单独加 ORDER BY 或 LIMIT(除非用括号包成子查询)。
- 错误写法:
(SELECT ...) UNION ALL (SELECT ...) ORDER BY id LIMIT 10→ 报错ERROR 1221 (HY000) - 正确做法:用括号包住整个
UNION ALL,再套一层查询:SELECT * FROM (SELECT ... UNION ALL SELECT ...) AS tmp ORDER BY id LIMIT 10 - 如果只想取某一边的最新 5 条,必须在那一边先做子查询:
(SELECT ... ORDER BY created_at DESC LIMIT 5) UNION ALL (SELECT ...) - 大数据量下,外部
ORDER BY会导致全量合并后再排序,内存/磁盘压力陡增——这点最容易被忽略
真正影响性能的从来不是 UNION ALL 本身,而是每个子查询是否高效、是否提前过滤、是否用了覆盖索引。别只盯着“拼接”这一步,先确保每个 SELECT 都能走索引、少回表、不扫全表。


















