MySQL集合操作详解:UNION与UNION ALL的区别及性能优化

小石头
小石头
发布时间:2026-10-14| 5人浏览过
原创

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 的核心逻辑如下:

  1. 创建一个临时虚拟表来存储合并后的数据。
  2. 为该临时表的列添加唯一索引(Unique Index)。
  3. 将各个子查询的结果逐行插入该临时表。
  4. 由于唯一索引的存在,插入过程中若发现键值冲突(即重复数据),则自动丢弃新行。
  5. 最后返回去重后的虚拟表。

这意味着,只有当 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的详细对比与实战应用,更多关于数据库查询优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。