MySQL集合操作详解:UNION与UNION ALL的区别及性能优化
MySQL中的集合操作是对多个查询结果集进行垂直合并的技术手段,主要包含UNION和UNION ALL两种方式。理解它们在数据去重、底层实现机制及执行效率上的差异,对于编写高效且准确的SQL语句至关重要。
集合操作的基本概念
与将多张表的列进行水平拼接的“联接(JOIN)”操作不同,集合操作是一种垂直操作。它要求参与合并的两个或多个输入结果集必须满足以下条件:
- 列数相同:各SELECT语句返回的列数量必须一致。
- 数据类型兼容:对应位置的列数据类型应相同或能够隐式转换。
- 列名继承:最终结果集的列名由第一个SELECT语句决定。
MySQL目前主要支持两种集合操作:UNION DISTINCT(通常简写为 UNION)和 UNION ALL。
准备测试环境
为了直观展示集合操作的效果,我们需要创建两张具有相同结构的测试表,并插入部分重叠的数据。
第1步:创建测试表
在数据库中执行以下DDL语句,构建表结构和索引:
create table table1
(aid int not null auto_increment,
title varchar(20),
tag varchar(10),
primary key(aid))
engine=innodb default charset=utf8;
create table table2
(bid int not null auto_increment,
title varchar(20),
tag varchar(10),
primary key(bid))
engine=innodb default charset=utf8;
第2步:插入测试数据
向表中填充数据,注意观察两表中存在的重复项(如 article1/MySQL):
insert into table1(aid, title, tag) values(1, 'article1', 'MySQL');
insert into table1(aid, title, tag) values(2, 'article2', 'PHP');
insert into table1(aid, title, tag) values(3, 'article3', 'CPP');
insert into table2(bid, title, tag) values(1, 'article1', 'MySQL');
insert into table2(bid, title, tag) values(2, 'article2', 'CPP');
insert into table2(bid, title, tag) values(3, 'article3', 'C');
UNION(DISTINCT)操作详解
UNION 指令在合并结果集后,会自动去除完全相同的重复行。这是其默认行为,因此 UNION DISTINCT 可省略为 UNION。
语法结构与执行示例
基本语法如下:
SELECT column,... FROM table1
UNION
SELECT column,... FROM table2;
当执行以下查询时:
(select * from table1) union (select * from table2);
得到的结果集如下:
+-----+----------+-------+
| aid | title | tag |
+-----+----------+-------+
| 1 | article1 | MySQL |
| 2 | article2 | PHP |
| 3 | article3 | CPP |
| 2 | article2 | CPP |
| 3 | article3 | C |
+-----+----------+-------+
观察重点:表1和表2中ID为1、内容为article1 / MySQL的记录仅出现了一次。这是因为UNION认为这两条记录在所有字段上完全一致,从而判定为重复项并被过滤。
底层实现机制
MySQL处理 UNION DISTINCT 的核心逻辑如下:
- 创建一个临时虚拟表来存储合并后的数据。
- 为该临时表的列添加唯一索引(Unique Index)。
- 将各个子查询的结果逐行插入该临时表。
- 由于唯一索引的存在,插入过程中若发现键值冲突(即重复数据),则自动丢弃新行。
- 最后返回去重后的虚拟表。
这意味着,只有当 SELECT 所选的所有字段值完全相同时,才会被视为重复。
UNION ALL 操作详解
与 UNION 不同,UNION ALL 仅仅简单地合并两个结果集,不进行任何去重处理。无论数据是否重复,所有行都会被原样返回。
执行效果对比
使用相同的测试数据,执行 UNION ALL 查询:
(select * from table1) union all (select * from table2);
结果为:
+-----+----------+-------+
| aid | title | tag |
+-----+----------+-------+
| 1 | article1 | MySQL |
| 2 | article2 | PHP |
| 3 | article3 | CPP |
| 1 | article1 | MySQL |
| 2 | article2 | CPP |
| 3 | article3 | C |
+-----+----------+-------+
可以看到,article1 / MySQL 这条记录出现了两次,分别来自 table1 和 table2。此外,由于不去重,table1 和 table2 中 ID 不同但内容相似的 article2/CPP 也同时保留(因为它们的主键 aid/bid 不同,导致整行记录不完全相同,但在某些字段比对场景下需注意业务逻辑上的“重复”定义)。
性能分析与最佳实践
在处理大量数据时,选择合适的集合操作对性能影响显著:
- UNION 的性能开销:由于需要建立唯一索引并进行插入检查(查重),其CPU和内存消耗高于简单的物理追加。如果数据量巨大且确认无重复,使用 UNION 会浪费资源。
- UNION ALL 的高效性:它只是简单地将结果集堆叠在一起,速度最快。适用于确定数据源之间没有交集,或者即使有重复也希望保留的场景。
建议:如果你明确知道参与 UNION 操作的两个集合中没有重复数据,或者你不需要去重,请始终优先使用 UNION ALL 以提升查询效率。
常见问题排查
Q: 为什么 UNION 结果集中包含了看起来相似但主键不同的行?
A: UNION 的去重是基于整个选择列的组合。在主键(如 aid, bid)不同但业务内容(title, tag)相同的案例中,如果 SELECT * 包含了主键,则记录被视为不同。若要按业务内容去重,需确保 SELECT 列表仅包含业务字段,或使用 GROUP BY 辅助判断。
以上就是MySQL中集合操作UNION与UNION_ALL的详细对比与实战应用,更多关于数据库查询优化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













