union all 比 union 快是因为它不去重、不排序、不写临时表,仅顺序拼接结果;而 union 隐式执行 distinct 和排序,大数据量易触发磁盘临时表或内存溢出。

UNION ALL 为什么比 UNION 快
UNION ALL 不去重、不排序、不写临时表,只是把各 SELECT 结果顺序拼接;UNION 则隐式加 DISTINCT + 隐式排序,数据量一过几万行就容易触发磁盘临时表甚至内存溢出。哪怕两个子查询天然无重复(比如按日期分区的日志表),用 UNION 也白白多一次全量扫描。
列数、顺序、类型必须严格对齐
报错 ERROR 1222 (21S01): The used SELECT statements have a different number of columns 是最常见拦路虎。MySQL 只校验「位置」和「表达式类型兼容性」,不看字段名:
- 每个
SELECT的列数必须完全一致;SELECT *是高危操作,表结构一变就崩 - 顺序必须语义对齐:第一个查
id, name, status,后面就不能写成name, id, status - 类型要兼容:
INT和DECIMAL可转,VARCHAR(10)和VARCHAR(100)能拼,但TINYINT和DATETIME强行UNION ALL很可能报错或返回0/'0000-00-00' - 缺字段就用
NULL AS city或CAST('' AS VARCHAR(50)) AS city显式占位
ORDER BY 和 LIMIT 必须写在子查询里
UNION ALL 是集合操作,不是嵌套结构。你不能在末尾直接加 ORDER BY created_at DESC LIMIT 100,MySQL 会报 ERROR 1221 (HY000):
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
- 要取某一边最新 5 条(比如日志表),必须先包成子查询:
(SELECT * FROM log_202605 ORDER BY created_at DESC LIMIT 5) - 想整体取 Top-N,得每个分支都做裁剪:
(SELECT ... ORDER BY score DESC LIMIT 20) UNION ALL (SELECT ... ORDER BY score DESC LIMIT 20) ORDER BY score DESC LIMIT 20 - 外层
ORDER BY仍需保留——UNION ALL不保证顺序 - 大数据量下,外部
ORDER BY会导致全量合并后再排序,内存/磁盘压力陡增
索引必须为每个子查询单独建
UNION ALL 不跨查询合并索引,每个 SELECT 是独立优化的:
- 别指望一个联合索引覆盖全部;
t1(status, created_at, id, name)和t2(type, updated_at, id, name)得分别建 - WHERE 条件字段没索引?照样全表扫;
LIKE '%abc'或DATE(created_at)会让对应索引失效 - 避免
SELECT *,只查必要字段,减少 I/O 和回表 - 公共过滤条件(如
AND deleted = 0)必须复制到每个子查询里,不能只写在外层
真正卡慢的从来不是 UNION ALL 本身,而是某个子查询没走索引、没提前过滤、字段太宽导致临时表落盘——这些地方最容易被忽略。










