在SQL查询的实际应用中,经常会遇到需要把多个独立查询的结果整合到一起的需求,比如统计不同部门的数据、合并分表存储的同结构数据等,这时候就需要用到结果集合并操作符。UNION和UNION ALL是SQL标准中定义的两个用于合并结果集的操作符,二者功能相似但特性不同,适用的场景也有明显区别。

UNION和UNION ALL的基本语法
两个操作符的语法结构基本一致,都是放在多个SELECT语句之间,用来合并这些SELECT语句返回的结果集,要求每个SELECT语句返回的列数、列的数据类型必须兼容。
UNION语法
UNION会自动对合并后的结果集进行去重,并且默认按照第一列进行升序排序。
-- 合并两个表的学生数据,自动去重排序 SELECT student_id, student_name FROM class_a UNION SELECT student_id, student_name FROM class_b;
UNION ALL语法
UNION ALL直接合并所有结果集,不会进行去重和排序操作,保留所有重复的数据行。
-- 合并两个表的学生数据,保留所有重复行 SELECT student_id, student_name FROM class_a UNION ALL SELECT student_id, student_name FROM class_b;
两者的核心差异对比
通过以下维度可以清晰看到两个操作符的不同特性:
| 对比维度 | UNION | UNION ALL |
|---|---|---|
| 去重处理 | 会对合并后的结果集进行去重 | 不会去重,保留所有原始行 |
| 排序处理 | 默认对结果集按第一列升序排序 | 不排序,结果顺序为各SELECT语句返回顺序的组合 |
| 执行效率 | 较低,需要额外去重排序开销 | 较高,无额外处理开销 |
| 适用场景 | 需要最终结果无重复的场景 | 确认结果无重复或需要保留重复数据的场景 |
性能差异的具体原因分析
UNION和UNION ALL的性能差异主要来自于执行过程中的额外操作:
- 去重开销:UNION需要对合并后的所有数据行进行去重判断,通常会使用排序或者哈希表的方式实现,当结果集数据量较大时,这个过程的资源消耗会非常明显。而UNION ALL直接拼接结果,不需要做任何去重判断,几乎没有额外开销。
- 排序开销:UNION默认会对最终结果集进行排序,排序操作本身就需要消耗CPU和内存资源,尤其是数据量大的时候排序的耗时会增加很多。UNION ALL不会触发排序操作,执行速度更快。
实际案例验证性能差异
我们可以创建两个测试表,插入大量数据来对比两者的执行耗时:
-- 创建测试表
CREATE TABLE test_table1 (
id INT PRIMARY KEY,
content VARCHAR(50)
);
CREATE TABLE test_table2 (
id INT PRIMARY KEY,
content VARCHAR(50)
);
-- 插入10万条测试数据到两个表
DELIMITER //
CREATE PROCEDURE insert_test_data()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 100000 DO
INSERT INTO test_table1 VALUES(i, CONCAT('content_', i));
INSERT INTO test_table2 VALUES(i, CONCAT('content_', i));
SET i = i + 1;
END WHILE;
END //
DELIMITER ;
CALL insert_test_data();
分别执行UNION和UNION ALL查询,观察执行计划和执行耗时:
-- 执行UNION查询,查看执行计划 EXPLAIN SELECT id, content FROM test_table1 UNION SELECT id, content FROM test_table2; -- 执行UNION ALL查询,查看执行计划 EXPLAIN SELECT id, content FROM test_table1 UNION ALL SELECT id, content FROM test_table2;
从执行计划可以看到,UNION查询会多出Using temporary和Using filesort的标识,说明执行过程中使用了临时表和文件排序,这两个操作都是比较耗时的。而UNION ALL的执行计划中没有这些额外操作,执行速度会快很多。
使用建议
在实际开发中选择使用哪个操作符,可以参考以下原则:
- 如果确认多个结果集之间不存在重复数据,或者需要保留重复数据,优先使用UNION ALL,能显著提升查询性能。
- 只有当明确需要最终结果集去重,且无法通过其他方式提前避免重复时,再使用UNION。
- 如果UNION之后还需要对结果进行排序,建议手动指定排序规则,避免默认的排序带来额外开销,或者在应用层处理排序逻辑。
注意:使用UNION或UNION ALL合并结果集时,每个SELECT语句返回的列数必须相同,对应列的数据类型必须兼容,否则查询会直接报错。