在SQL查询中,当我们需要把多个独立的查询结果拼接成一个结果集时,UNION和UNION ALL是两个最常用的操作符,两者的核心差异集中在是否对合并后的结果进行去重处理,这也直接影响了查询的执行效率和最终结果的准确性。

UNION和UNION ALL的基础用法
两者的基础语法结构完全一致,都是将多个SELECT语句的结果合并,要求每个SELECT语句返回的列数、列的数据类型必须兼容。基础的语法格式如下:
-- UNION 语法 SELECT column1, column2 FROM table1 UNION SELECT column1, column2 FROM table2; -- UNION ALL 语法 SELECT column1, column2 FROM table1 UNION ALL SELECT column1, column2 FROM table2;
两者的核心区别
1. 去重机制不同
UNION在合并结果集之后,会自动对最终的结果进行去重操作,删除所有重复的行;而UNION ALL只会简单地将多个结果集按顺序拼接,不会做任何去重处理,即使存在完全相同的行也会全部保留。
我们可以通过一个简单的示例来验证这个差异,假设我们有两个测试表,表结构和数据如下:
-- 创建测试表并插入数据
CREATE TABLE test_a (
id INT,
name VARCHAR(20)
);
INSERT INTO test_a VALUES (1, '张三'), (2, '李四'), (3, '王五');
CREATE TABLE test_b (
id INT,
name VARCHAR(20)
);
INSERT INTO test_b VALUES (2, '李四'), (3, '王五'), (4, '赵六');
分别使用UNION和UNION ALL合并两个表的结果:
-- 使用UNION合并,结果会自动去重 SELECT id, name FROM test_a UNION SELECT id, name FROM test_b; -- 执行结果: -- 1 张三 -- 2 李四 -- 3 王五 -- 4 赵六 -- 使用UNION ALL合并,结果保留所有行 SELECT id, name FROM test_a UNION ALL SELECT id, name FROM test_b; -- 执行结果: -- 1 张三 -- 2 李四 -- 3 王五 -- 2 李四 -- 3 王五 -- 4 赵六
2. 性能表现不同
由于UNION需要执行去重操作,数据库在执行UNION时,通常会对合并后的结果集进行排序或者使用哈希表来识别重复行,这个过程会消耗额外的CPU和内存资源,尤其是当结果集数据量较大时,性能损耗会非常明显。而UNION ALL不需要做任何额外的处理,只需要按顺序拼接结果,执行效率远高于UNION。
我们可以通过执行计划来直观看到两者的性能差异,以MySQL为例,UNION的执行计划中会出现Using temporary(使用临时表)和Using filesort(使用文件排序)的标识,而UNION ALL的执行计划则没有这些额外的操作。
如何根据去重需求选择合并方式
1. 需要去重的场景选择UNION
当业务需求明确要求合并后的结果不能存在重复行时,必须使用UNION。比如我们需要统计全公司的员工名单,员工可能同时存在于正式员工表和外包员工表中,此时合并两个表的结果就需要去重,避免同一个员工出现多次。
-- 合并正式员工和外包员工名单,去重 SELECT employee_id, employee_name FROM regular_employee UNION SELECT employee_id, employee_name FROM outsourced_employee;
2. 不需要去重的场景选择UNION ALL
如果业务场景本身就不会产生重复数据,或者重复数据是合理需要的,那么优先选择UNION ALL,这样可以避免不必要的性能损耗。常见的场景包括:
- 合并分表数据:比如按月份拆分订单表,查询全年订单时合并12个月的分表数据,由于分表的数据按时间拆分,本身不会重复,用UNION ALL效率更高。
- 需要保留重复记录的场景:比如统计用户的操作日志,同一个用户可能多次操作同一条数据,这些重复记录都是有效数据,需要全部保留。
-- 合并12个月的订单分表,不需要去重 SELECT order_id, user_id, amount FROM order_202401 UNION ALL SELECT order_id, user_id, amount FROM order_202402 -- 后续继续拼接其他月份的分表
使用注意事项
在使用这两个操作符时,还需要注意以下几点:
- 参与合并的每个SELECT语句返回的列数必须一致,列的数据类型也需要兼容,否则会直接报错。
- UNION的去重是对所有列的组合进行去重,只要有一列的值不同,就不会被判定为重复行。
- 如果需要对合并后的结果排序,ORDER BY子句只能放在最后一个SELECT语句之后,不能在每个SELECT语句中单独加ORDER BY。
注意:不要为了省事默认使用UNION,在确认不需要去重的场景下,使用UNION ALL可以大幅提升查询性能,尤其是在处理大数据量结果集时,性能差异可能达到数倍甚至数十倍。