跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

mysql如何处理Union与UnionAll的执行差异_临时表去重流程解析

UNION强制走临时表排序去重,UNION ALL完全跳过该逻辑;前者等价于SELECT DISTINCT * FROM (子查询UNION ALL)并触发Using temporary/Using filesort,后者直接流式追加结果、无去重开销、首行延迟低。

UNION 一定走临时表去重,UNION ALL 绝不走;这不是可选逻辑,而是 MySQL 优化器的硬性执行路径。 UNION 底层强制物化 + 排序去重 MySQL 不会直接在流式结果上做哈希比对。它先把所有子查询结果用
UNION ALL
拼成一个中间集,再建临时表、排序、逐行扫描去重——等价于执行:
SELECT DISTINCT * FROM (SELECT ... UNION ALL SELECT ...) AS t
。 常见现象: EXPLAIN 显示
Using temporary; Using filesort
,哪怕子查询本身已有序 字段含大量
NULL
时,哈希去重失效,优化器退回到基于磁盘的排序,I/O 暴涨 子查询带
ORDER BY
或
LIMIT
,可能触发两层临时表(子查询物化 + 合并去重) UNION ALL 完全跳过去重逻辑 各子查询独立执行,结果直接追加到输出流,不建临时表、不排序、不比较重复行。 关键事实:
EXPLAIN
中看不到
Using temporary
,Extra 字段通常为空或仅含子查询自身信息 即使两子查询返回完全相同的数据,
UNION ALL
也原样保留两份 天然支持流式返回和并行执行,首行延迟低,适合日志归档、分表查询等场景 ORDER BY 和 LIMIT 必须写在外层 MySQL 不允许在子查询里写
ORDER BY
或
LIMIT
来控制合并后顺序——语法虽可通过,但语义无效。 错误写法:
(SELECT id FROM t1 ORDER BY id LIMIT 10) UNION (SELECT id FROM t2 ORDER BY id LIMIT 10)
MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载 正确写法:
(SELECT id FROM t1) UNION ALL (SELECT id FROM t2) ORDER BY id LIMIT 10
若真要先局部排序再合并,得用派生表:
(SELECT * FROM (SELECT id FROM t1 ORDER BY id LIMIT 10) AS t1s) UNION ALL ...
,但会强制物化,性能更差。 NULL 值多时 UNION 性能断崖式下跌 MySQL 判断重复行时,
NULL = NULL
返回
UNKNOWN
,但去重逻辑将其视为相等。这导致哈希算法无法稳定分区,优化器大概率放弃哈希去重,转而使用磁盘排序。 实测中,当结果集中超过 30% 的字段为
NULL
,UNION 耗时可能比 UNION ALL 高出 10 倍以上,且
tmp_table_size
不足时频繁写磁盘临时表。 容易被忽略的一点:这种性能劣化不会在 EXPLAIN 中显式提示,只能靠 FORMAT=JSON 查看
"union_result": {"using_temporary_table": true}
和实际执行时间反推。

相关文章