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 判断重复行时,