UNION报错列数不匹配因各SELECT字段数量不等;UNION去重开销大,UNION ALL仅追加;EXPLAIN不显示全部执行计划,需单独分析;字符集冲突需显式指定COLLATE。

为什么 UNION 报错说列数不匹配?
最常见的是两个 SELECT 返回的字段数量不一致,MySQL 会直接报错 ERROR 1222 (21000): The used SELECT statements have a different number of columns。这不是类型问题,是纯数量对不上。
- 检查每个
SELECT的SELECT子句,数清楚逗号分隔的表达式个数(*算作一个,但实际展开后必须和另一侧列数一致) - 别依赖
SELECT *和SELECT a,b,c混用 —— 表结构一旦变更,*展开列数可能突变 - 如果真要补列,用
NULL或''占位,但需注意类型隐式转换:比如SELECT id, name FROM t1 UNION SELECT id, 0 FROM t2可能因name是VARCHAR而0被转成字符串,但更稳妥的是显式写CAST(0 AS CHAR)
UNION ALL 和 UNION 性能差十倍?
不是“差十倍”,而是去重逻辑本身开销巨大:UNION 需构建临时唯一哈希表或排序去重,而 UNION ALL 只是追加结果集。尤其当结果行数过万、字段含长文本或无索引时,差异立刻暴露。
- 确认业务是否真的需要去重 —— 很多场景下,应用层 dedup 更可控(比如 Python 用
set(tuple(row) for row in results)) - 如果必须用
UNION,确保参与查询的字段在各自表上有合适索引,减少中间结果体积 - 避免在
UNION外再套一层ORDER BY—— MySQL 5.7+ 允许只在最后加ORDER BY,但若提前加了子查询排序,可能触发额外临时表
调试时怎么看到 UNION 各部分的实际执行计划?
MySQL 的 EXPLAIN 对集合操作支持有限:它只显示第一个 SELECT 的执行计划,后续部分完全不展示。不能靠它判断第二段是不是全表扫描。
- 把每个
SELECT单独拎出来跑EXPLAIN FORMAT=TREE(8.0+)或EXPLAIN FORMAT=TRADITIONAL,逐个看type、rows、Extra - 用
SELECT ... INTO OUTFILE或临时表分别保存各部分结果,对比行数和数据分布,快速定位哪一段膨胀得离谱 - 开启慢查询日志并设置
long_query_time = 0,抓取完整 SQL 执行耗时,再结合SHOW PROFILE FOR QUERY N(需先SET profiling = 1)看各阶段耗时占比
字符集冲突导致 UNION 直接失败?
错误信息通常是 ERROR 1267 (HY000): Illegal mix of collations。本质是两个结果集的字段用了不同校对规则(如 utf8mb4_0900_as_cs vs utf8mb4_general_ci),MySQL 无法自动统一比较逻辑。
- 查字段校对集:
SHOW FULL COLUMNS FROM table_name LIKE 'col_name',看Collation列 - 强制统一:在对应
SELECT中用COLLATE utf8mb4_0900_as_cs显式指定,例如SELECT name COLLATE utf8mb4_0900_as_cs FROM t1 - 长期解法是修改表/列默认校对集:
ALTER TABLE t1 MODIFY name VARCHAR(100) COLLATE utf8mb4_0900_as_cs,但需评估存量数据影响
SELECT 单独执行是否真的返回预期结构和数据量。很多人一上来就改 UNION 写法,却没发现其中一段 SQL 本身已因 JOIN 条件错误返回了几百万行。










