mysql 的 union 用于合并两个或多个 select 语句的结果集,并自动去除重复行(相当于对结果集执行 distinct)。
1. 基本语法与核心规则
select column1, column2 from table1 union [all | distinct] select column1, column2 from table2;
强制性规则:
- 列数必须相同:两个 select 返回的列数必须一致
- 数据类型兼容:对应位置的列类型不必完全相同,但必须可隐式转换(如 int 和 decimal)
- 列名继承:结果集的列名取自第一个 select 语句
- order by 位置:只能放在最后一个 select 之后,且排序依据必须是第一个 select 的列名或别名
2. union vs union all
| 特性 | union (distinct) | union all |
|---|---|---|
| 去重 | 自动去重,行唯一 | 保留所有行,包括重复 |
| 性能 | 需要临时表+哈希排序去重,较慢 | 直接追加结果,极快 |
| 使用场景 | 必须确保唯一性时 | 确定无重复或需要保留重复时 |
性能建议:除非业务需要去重,否则优先使用 union all。去重操作需要创建临时表、哈希比较和额外排序,大数据量时性能差距巨大。
3. 实际应用场景
场景 a:合并相似结构表(如分表)
-- 查询 2023 和 2024 年的订单(假设按年分表) select order_id, amount, created_at from orders_2023 union all select order_id, amount, created_at from orders_2024 order by created_at desc limit 20;
场景 b:多维度统计报表
select 'vip用户' as user_type, count(*) as cnt from users where level >= 8 union all select '普通用户', count(*) from users where level between 1 and 7 union all select '访客', count(*) from users where level = 0;
场景 c:数据补全与兜底查询
-- 先查缓存表,若无结果再查主表(常见于配置表) select config_value from config_cache where config_key = 'site_name' union all select config_value from config where config_key = 'site_name' limit 1;
4. 进阶用法
带排序和分页
(select id, name from products where category = 'a' order by price desc limit 10) union all (select id, name from products where category = 'b' order by price desc limit 10) order by price desc limit 10;
注意:子查询中的 order by 必须配合 limit 才生效,否则会被优化器忽略。
混合聚合与明细
select city, sales_amount, null as detail from sales_summary union all select city, amount, concat(product_name, ':', quantity) from sales_detail;
5. 性能优化要点
- 索引利用:每个 select 独立使用索引,union 本身不走索引
- 减少数据集:在子查询中先
where过滤,避免传递大量数据到 union 层 - 避免临时表写入:
union distinct会创建内存临时表(或磁盘临时表,若过大),可通过set tmp_table_size调优 - 并行执行:mysql 8.0.19+ 对非相关子查询的 union 可能启用并行查询
6. 常见陷阱
-- ❌ 错误:列数不匹配 select id, name from t1 union select id from t2; -- error 1222 -- ❌ 错误:order by 位置错误 select * from t1 order by id union select * from t2; -- error 1221 -- ✅ 正确写法 select * from t1 union select * from t2 order by id; -- 使用第一个 select 的列名排序
7. django orm 中的 union
如果你在使用 django(看你之前关注过 django 源码),可以这样使用:
from django.db.models import q
# queryset.union() 默认使用 union all
qs1 = user.objects.filter(status='active').values('name', 'email')
qs2 = user.objects.filter(is_staff=true).values('name', 'email')
# union all
combined = qs1.union(qs2, all=true)
# union (去重)
combined_distinct = qs1.union(qs2) # 或 all=false
注意:django 的 union() 会强制转换为 sql 的 union,且 queryset 被求值后返回的是列表而非 queryset,无法继续链式过滤。
总结:union all 是合并结果集的高性能首选,union (distinct) 仅在需要去重时使用。始终确保子查询列数一致,并在应用层处理复杂的排序逻辑。
到此这篇关于mysql中union关键字的实现示例的文章就介绍到这了,更多相关mysql union关键字内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论