
1. 理解UNION与UNION ALL的本质区别在SQL查询中UNION和UNION ALL都是用于合并两个或多个SELECT语句结果集的操作符但它们的处理方式存在关键差异。我们先从一个实际案例开始假设你需要合并2022年和2023年的销售数据表两个表结构相同但包含部分重复记录如跨年续费的客户。UNION ALL是最直接的合并方式它简单地将两个结果集叠加在一起不做任何去重处理。其执行过程相当于执行第一个SELECT语句获取结果集A执行第二个SELECT语句获取结果集B将B的所有记录直接追加到A的末尾而UNION则在合并后会进行去重操作其执行流程为执行第一个SELECT语句获取结果集A执行第二个SELECT语句获取结果集B将B追加到A后对整个结果集执行DISTINCT操作关键区别UNION ALL保留所有记录包括重复项UNION会自动去除完全相同的行。这个差异直接影响查询结果和性能表现。2. 性能对比与底层实现机制从数据库引擎的角度看UNION ALL由于不需要去重其执行计划通常显示为简单的Concatenation操作。而UNION的执行计划会包含Sort和Distinct等额外步骤这在处理大数据集时会产生显著性能差异。我曾在实际项目中处理过约500万条记录的合并使用UNION ALL执行时间约1.2秒使用UNION执行时间达到8.7秒性能差距主要来自排序开销UNION需要对合并后的结果进行排序以便去重临时表使用多数数据库会创建临时表来处理UNION的去重操作内存消耗去重操作需要更多内存资源在MySQL中可以通过EXPLAIN命令查看两者的执行计划差异-- UNION ALL的执行计划 EXPLAIN SELECT * FROM sales_2022 UNION ALL SELECT * FROM sales_2023; -- UNION的执行计划 EXPLAIN SELECT * FROM sales_2022 UNION SELECT * FROM sales_2023;3. 使用场景选择指南3.1 必须使用UNION ALL的情况明确需要保留重复记录时如日志分析、全量数据统计等场景性能敏感的大数据量操作当确认数据源无重复或重复不影响业务逻辑时分表查询合并如按月分表的订单数据合并统计3.2 应该使用UNION的情况需要去重的统计分析如计算唯一用户数多来源数据整合从不同系统获取的数据可能存在重复结果集需要精确去重如生成不重复的报告数据实际案例在电商平台的用户行为分析中我们经常需要合并来自PC端和移动端的访问记录。如果同一个用户在两个平台都有操作使用UNION ALL会保留两条记录适合分析访问频次而UNION则只保留一条适合分析覆盖用户量。4. 高级使用技巧与注意事项4.1 数据类型与列匹配UNION操作要求各SELECT语句的列数相同且对应列的数据类型必须兼容。常见错误包括列数不一致数据类型不匹配如VARCHAR与INT合并排序规则冲突如Illegal mix of collations错误解决方案-- 显式类型转换示例 SELECT CAST(user_id AS CHAR) AS id, user_name FROM users UNION SELECT order_id, customer_name FROM orders;4.2 排序与LIMIT的使用在合并查询中使用ORDER BY和LIMIT时需特别注意-- 错误写法ORDER BY不能用于单个SELECT子句 SELECT * FROM table1 ORDER BY col1 UNION SELECT * FROM table2; -- 正确写法ORDER BY应用于最终结果 (SELECT * FROM table1) UNION (SELECT * FROM table2) ORDER BY col1 LIMIT 10;4.3 视图与子查询中的使用在创建视图或子查询时UNION/UNION ALL的行为需要特别注意-- 创建包含UNION的视图 CREATE VIEW combined_sales AS SELECT * FROM sales_2022 UNION ALL SELECT * FROM sales_2023; -- 使用视图时的索引提示 SELECT /* INDEX(combined_sales idx_sales_date) */ * FROM combined_sales WHERE sale_date 2023-01-01;5. 常见问题排查与优化5.1 性能优化方案索引利用确保UNION各子查询的WHERE条件能利用索引减少列数只SELECT必要的列避免SELECT *分阶段处理对大表先过滤再UNION优化示例-- 优化前 SELECT * FROM large_table1 UNION SELECT * FROM large_table2; -- 优化后 SELECT id, name FROM large_table1 WHERE create_time 2023-01-01 UNION SELECT id, name FROM large_table2 WHERE create_time 2023-01-01;5.2 错误处理常见错误包括Illegal mix of collations字符集排序规则不一致-- 解决方案使用COLLATE统一排序规则 SELECT user_name COLLATE utf8mb4_general_ci FROM users UNION SELECT customer_name COLLATE utf8mb4_general_ci FROM customers;数据类型不匹配如尝试合并字符串和数字列-- 错误示例 SELECT user_ || id FROM users UNION SELECT id FROM departments; -- 类型不匹配内存不足处理大数据量UNION时可能出现的错误-- 解决方案分批处理或使用UNION ALL配合应用层去重6. 实际业务场景应用案例6.1 电商平台数据合并在年度销售报告生成时我们需要合并各季度的销售数据-- 保留所有订单记录包括退换货产生的重复 SELECT order_id, product_id, sale_amount FROM q1_orders WHERE status ! cancelled UNION ALL SELECT order_id, product_id, sale_amount FROM q2_orders WHERE status ! cancelled -- ...其他季度6.2 多平台用户整合合并来自网站、APP和小程序的用户访问记录-- 计算独立访客数使用UNION去重 SELECT DISTINCT user_id FROM ( SELECT user_id FROM web_visits WHERE visit_date CURRENT_DATE UNION SELECT user_id FROM app_visits WHERE visit_date CURRENT_DATE UNION SELECT user_id FROM mini_program_visits WHERE visit_date CURRENT_DATE ) AS combined_visits;6.3 历史数据归档查询查询当前数据和历史归档数据的组合结果-- 当前活跃产品历史归档产品需要去重 SELECT product_id, product_name FROM active_products UNION SELECT product_id, product_name FROM archived_products ORDER BY product_name;7. 不同数据库的实现差异虽然UNION和UNION ALL是SQL标准操作但不同数据库管理系统存在一些实现差异7.1 MySQL/MariaDB特性默认使用临时表处理UNION查询8.0版本对UNION ALL有优化支持hash join等新特性支持UNION DISTINCT语法与UNION等效7.2 SQL Server特性提供UNION与UNION ALL的并行执行计划支持在UNION结果上直接创建索引视图对大型UNION查询有特定的优化提示7.3 PostgreSQL特性支持UNION/UNION ALL的并行查询可以对UNION子查询分别设置优化器提示提供更灵活的类型自动转换机制示例对比-- MySQL中的UNION优化提示 SELECT * FROM table1 UNION /* MERGE_UNION(t1,t2) */ SELECT * FROM table2; -- SQL Server中的OPTION提示 SELECT * FROM table1 UNION SELECT * FROM table2 OPTION (MERGE UNION);8. 最佳实践总结根据多年数据库开发经验我总结出以下UNION/UNION ALL使用原则默认优先使用UNION ALL除非明确需要去重否则应首选性能更好的UNION ALL早期过滤原则在UNION之前尽可能过滤数据减少处理的数据量-- 好先过滤再UNION SELECT * FROM large_table WHERE condition1 UNION ALL SELECT * FROM large_table WHERE condition2 -- 差先UNION再过滤 SELECT * FROM large_table UNION ALL SELECT * FROM large_table WHERE condition1 OR condition2列裁剪原则只选择必要的列避免SELECT *-- 好只选择需要的列 SELECT id, name FROM table1 UNION ALL SELECT id, name FROM table2 -- 差选择所有列 SELECT * FROM table1 UNION ALL SELECT * FROM table2类型一致原则确保合并的列具有兼容的数据类型必要时显式转换监控调整原则对生产环境中的UNION查询进行性能监控必要时调整或重写在实际项目中我曾遇到一个典型案例一个报表查询原本使用UNION执行需要15秒在确认业务逻辑允许重复数据后改为UNION ALL执行时间降至1.3秒同时减少了数据库60%的CPU使用率。这个案例充分说明了正确选择合并操作符的重要性。