首页 > 数据库 >MySQL UNION操作为何推荐使用UNION ALL?

MySQL UNION操作为何推荐使用UNION ALL?

来源:互联网 2026-07-04 08:49:05

别再被UNION的“保险”诱惑了,性能差距比你想象的大得多 先丢个核心结论:UNION ALL 的性能往往比 UNION 高出不止一个数量级。原因很简单,UNION 在合并结果集之后会自动触发去重操作,这背后通常伴随隐式排序,进而产生临时表和文件排序。而 UNION ALL 则是将各个子查询的结果直

别再被UNION的“保险”诱惑了,性能差距比你想象的大得多

先丢个核心结论:UNION ALL 的性能往往比 UNION 高出不止一个数量级。原因很简单,UNION 在合并结果集之后会自动触发去重操作,这背后通常伴随隐式排序,进而产生临时表和文件排序。而 UNION ALL 则是将各个子查询的结果直接拼接,完全不碰数据内容。从执行计划上看,UNION 等价于 UNION ALL 再套一层 DISTINCT,这直接导致 Using temporaryUsing filesort 的出现,I/O 和 CPU 开销自然就上去了。

MySQL UNION操作为何推荐使用UNION ALL?

长期稳定更新的攒劲资源: >>>点此立即查看<<<

UNION ALL 比 UNION 快得多,因为它不触发去重逻辑

性能差距有多大?两个各返回 50 万行的子查询,用 UNION ALL 可能 200 毫秒内就流式返回,数据像流水一样从数据库里吐出。而 UNION 则会卡在 Using temporary; Using filesort 上,耗时数秒甚至直接内存溢出(OOM)都不奇怪。

如果你的查询出现以下情况,基本可以断定是 UNION 的去重逻辑在作祟:

  • 执行计划里出现了 Using temporaryUsing filesort
  • 查询响应时间随着结果集增长呈非线性飙升
  • 临时表空间(tmp_table_size / max_heap_table_size)被频繁打满

UNION 会悄悄改掉你的结果行数和顺序

这点非常隐蔽,但后果可能很严重。只要任意两行在所有列上完全相等,UNION 就会毫不留情地干掉一个。哪怕这两行来自不同的业务表,比如“正式员工”和“外包人员”里都叫“张三”、部门也相同,它也会被当作重复行过滤掉。这不是 bug,这就是 UNION 的设计行为。

更让人头疼的是顺序问题。UNION 的去重过程在 MySQL 8.0 以前尤其明显,会伴随隐式排序,导致最终结果的顺序完全不可控。而 UNION ALL 至少能忠实地保持各子查询的原始输出顺序——除非你显式加上 ORDER BY

来看几个典型的应用场景,就知道什么时候该用哪个了:

  • 合并按天分表的日志(比如 log_20260501log_20260502…)—— 数据天然不重复,直接用 UNION ALL
  • 跨库汇总用户注册数 —— 各库 ID 独立,不可能重复,用 UNION ALL
  • 补全缺失维度值(比如左连接后用 UNION ALL 加默认分类)—— 明确要保留所有行,用 UNION ALL

列对齐、类型兼容、ORDER BY 写法必须严格按规则来

无论是 UNION 还是 UNION ALL,它们都不是“智能拼接”。它们只认位置,不认字段名。下面这些写法,MySQL 都会直接报错:

  • SELECT name, id FROM t1 UNION SELECT id, name FROM t2 —— 列顺序错乱,第一列拼的是 t1.namet2.id,语义完全混乱
  • SELECT created_at FROM orders UNION SELECT order_time FROM history —— 类型不兼容,比如 DATETIMETIMESTAMP 在某些版本会直接报错
  • SELECT x FROM a ORDER BY x LIMIT 10 UNION SELECT y FROM b ORDER BY y LIMIT 10 —— 语法非法,MySQL 会抛出 ERROR 1221

正确的做法是什么?

  • 统一用 CAST()CONVERT(... USING utf8mb4) 显式转换数据类型
  • 所有子查询的列数、顺序、别名必须完全一致。比如,都统一写成 SELECT id AS uid, name AS fullname FROM ...
  • ORDER BY 只能放在整个查询的最后,并且只能引用列名或位置序号:... UNION ALL ... ORDER BY fullname
  • 如果想让每个子查询各自取 top N,就需要包一层子查询:(SELECT ... ORDER BY x LIMIT 10) UNION ALL (SELECT ... ORDER BY y LIMIT 10)

什么时候真该用 UNION?别靠感觉判断

只有当以下条件全部满足时,才值得考虑 UNION

  • 业务逻辑明确要求结果中每行全局唯一(比如合并多个来源的用户 ID,且 ID 是主键)
  • 你无法在子查询里通过 WHEREJOIN 提前排重
  • 数据量不大,或已经确认去重开销完全可控(比如总行数在几千以内)

如果只是“怕有重复所以保险起见”,那反而容易埋下隐患。比如某天上游数据逻辑变更,导致本不该去重的行被意外合并,这种问题回溯起来非常困难。更稳妥的做法是:先用 UNION ALL 查出全量数据,再用 SELECT DISTINCT 包一层。虽然性能可能稍差,但语义清晰、可调试,出了问题也容易定位。

最后,还有一个很容易被忽略的细节:即使两个表结构一模一样,UNION 也会把 NULLNULL 当作相等去重。但在很多业务场景里,NULL 的语义是“未知”,而不是“相同”。这一点在统计类查询中,很容易引发数据偏差,需要格外警惕。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备14008430号-1 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。