UNION去重并隐式排序,性能较低;UNION ALL不处理重复,性能高2–5倍;二者均要求列数、顺序及类型兼容,MySQL 8.0.31+才支持INTERSECT和EXCEPT,列名以首条SELECT为准,隐式类型转换易致精度丢失与索引失效。
MySQL 集合查询(UNION、UNION ALL、INTERSECT、EXCEPT)对新手不算友好——不是语法难,而是容易在语义理解、列对齐和隐式类型转换上栽跟头。
新手常以为 UNION 就是“去重合并”,UNION ALL 就是“直接拼接”,但实际影响远不止结果行数:
UNION 会触发隐式排序 + 去重,MySQL 内部可能临时创建唯一索引,数据量大时明显变慢;UNION ALL 完全跳过这步,性能通常高 2–5 倍SELECT 的列数、顺序、类型兼容性一致;若第一列是 INT,第二条的对应列是 VARCHAR,MySQL 会尝试转成字符串,可能导致 WHERE 条件失效或索引无法使用ORDER BY 只能加在最后一条语句后,且只能按最终结果集的列名或位置编号(如 OR
DER BY 1),不能写在单个 SELECT 后面SELECT id, name FROM users WHERE status = 1 UNION ALL SELECT user_id AS id, full_name AS name FROM admins WHERE active = 1 ORDER BY id;
很多教程没说清楚版本限制:MySQL 在 8.0.31 之前根本不支持 INTERSECT 和 EXCEPT。新手照着文档写,直接报错 ERROR 1064 (42000)。
INNER JOIN 或子查询:SELECT * FROM a WHERE id IN (SELECT id FROM b)
LEFT JOIN ... IS NULL,比用 NOT IN 更安全(后者遇到 NULL 会整个结果为空)INTERSECT 默认也去重,不带 ALL 关键字,这点和 UNION 行为不统一,容易混淆集合查询的结果列名以第一条 SELECT 为准,后续语句的别名会被忽略;更麻烦的是 MySQL 对类型的“宽松”处理:
DECIMAL(10,2),第二条是 FLOAT,最终列类型可能是 DOUBLE,精度丢失肉眼难察觉TEXT 和 VARCHAR(255) 混用时,UNION 可能强制转成 TEXT,导致 GROUP BY 或 ORDER BY 性能骤降CAST() 统一关键字段类型,比如:CAST(created_at AS DATETIME)
真正卡住新手的,往往不是会不会写 UNION,而是查出来结果“看起来对”,但分页错乱、统计不准、接口响应变慢——问题藏在类型隐式转换和执行计划里,得学会看 EXPLAIN FORMAT=TREE 输出里的 union_result 节点。