UNION 和 UNION ALL 的核心区别在哪
根本区别在于是否去重:
UNION会自动去除重复行,
UNION ALL完全不处理重复,直接拼接结果集。这意味着
UNION内部隐式执行了
DISTINCT操作,而
UNION ALL只是物理追加。
实际影响很直接:
UNION性能更低,尤其在大数据量时,需排序 + 去重
UNION ALL几乎无额外开销,执行更快 两者都要求各
SELECT子句列数相同、对应列类型兼容(MySQL 会尝试隐式转换) 列名以第一个
SELECT的字段名为准
什么时候必须用 UNION,不能用 UNION ALL
当你明确需要合并后结果唯一时,比如统计多个渠道的用户 ID 且不能重复计数,或拼接不同条件查出的主键集合用于后续
IN查询 —— 这时若用
UNION ALL,可能引入重复 ID 导致逻辑错误或性能下降(如子查询中重复值被多次匹配)。
典型场景包括:
多表联合去重取 ID 列表 分页前对多个来源数据统一去重再排序 和NOT IN/
LEFT JOIN ... IS NULL配合做排除逻辑,重复值会影响结果正确性
ORDER BY 和 LIMIT 在 UNION 中怎么写才合法
ORDER BY和
LIMIT不能出现在单个子查询里(除最外层),否则报错:
ERROR 1221 (HY000): Incorrect usage of UNION and ORDER BY。
正确写法是把整个
UNION当作一个派生表,或直接在最后加
ORDER BY和
LIMIT:
SELECT id, name FROM t1 UNION ALL SELECT id, name FROM t2 ORDER BY id DESC LIMIT 10;
注意:
ORDER BY中的字段名必须来自第一个
SELECT的列(或其别名) 如果想对每个子查询单独排序再合并,得用子查询包装:
(SELECT ... ORDER BY x LIMIT n) UNION ALL (SELECT ... ORDER BY y LIMIT m)
LIMIT放在末尾是对合并后整体生效;若要限制每个子查询,必须加括号并分别写
常见错误:列类型不一致导致 UNION 失败
MySQL 对
UNION各子查询对应列的类型有隐式转换规则,但不是万能的。比如
VARCHAR(10)和
TEXT合并可能触发警告或截断;
INT和
DECIMAL(10,2)通常可转,但
JSON和
TEXT混用会报错:
ERROR 1267 (HY000): Illegal mix of collations或类型不兼容。
稳妥做法:
显式用CAST()或
CONVERT()统一类型,例如:
CAST(created_at AS DATE)避免混用
NULL和非空字符串,可用
COALESCE(col, '')对齐 字符集/排序规则不一致时,用
COLLATE utf8mb4_0900_as_cs显式指定
真正容易被忽略的是:即使语句能跑通,隐式转换也可能悄悄改变数据表现——比如时间字段被转成字符串后排序失效,或者数字精度丢失。上线前务必用真实数据验证结果一致性。
