当前位置: 代码网 > it编程>数据库>Mysql > MySQL中多条查询结果纵向拼接(UNION/UNION ALL)优化指南

MySQL中多条查询结果纵向拼接(UNION/UNION ALL)优化指南

2026年07月24日 Mysql 我要评论
前言在日常开发中,我们经常需要把多条独立select查询的结果上下堆叠合并,也就是纵向拼接。很多人容易混淆两个概念:join:横向拼接,增加列;union / union all:纵向拼接,增加行。不

前言

在日常开发中,我们经常需要把多条独立select查询的结果上下堆叠合并,也就是纵向拼接。

很多人容易混淆两个概念:

  • join:横向拼接,增加列;
  • union / union all:纵向拼接,增加行。

不少开发直接上手写union,遇到大数据量直接触发慢查询;同时还有limit失效、排序异常、索引无法利用、跨表or改造等一系列踩坑点。

本文系统讲解mysql纵向拼接语法、底层差异、规范写法、高频陷阱以及线上最优实践。

一、什么是纵向拼接

  • 横向拼接(join):两张表根据关联字段左右合并,行数重组,字段增多
  • 纵向拼接(union系列):把多条查询结果上下堆叠,字段结构保持一致,行数累加

示意图通俗理解:

查询a结果:
id | name
1  | 张三

查询b结果:
id | name
2  | 李四

纵向拼接后:
id | name
1  | 张三
2  | 李四

二、基础语法与强制约束

纵向拼接依靠两个关键字:unionunion all

硬性规则(违反直接报错)

  1. 每条子查询列数量必须完全一致
  2. 对应位置字段数据类型尽量兼容;
  3. 最终字段名称由第一条select决定,后续子查询别名无效;
  4. 不推荐子查询使用select *,字段结构变更会直接引发异常。

基础示例:

-- 纵向拼接两条查询
select id, username from `user` where status = 1
union all
select id, access_key from `app_key` where status = 1;

三、union 和 union all核心区别(重中之重)

union

  1. 合并结果后自动全局去重
  2. mysql底层会创建临时表、执行排序比对重复;
  3. 执行计划大概率出现 using temporary; using filesort
  4. 性能较差,大数据量慎用。

union = union all + distinct 全局去重

union all

  1. 直接原样纵向拼接,不去重、不排序
  2. 无临时表、无全局排序开销;
  3. 性能远高于union,优先选用

直观对比测试

存在重复数据场景:

-- union:自动剔除重复行
select user_id from `user` where username = 'demo'
union
select user_id from `app_key` where access_key = 'demo_key';

-- union all:保留全部记录,包含重复
select user_id from `user` where username = 'demo'
union all
select user_id from `app_key` where access_key = 'demo_key';

四、业务需要去重该怎么写?

不推荐:直接使用 union

推荐方案:union all + 外层distinct

select distinct user_id from (
    select user_id from `user` where username = 'demo'
    union all
    select user_id from `app_key` where access_key = 'demo_key'
) t;

优势:优化器可以自主选择哈希去重,不一定强制排序,优化空间更大,线上标准写法。

五、高频踩坑:limit 与 order by 作用范围

陷阱1:不加括号,limit只会作用最后一条子查询

错误写法

select id,username from `user` limit 10
union all
select id,access_key from `app_key` limit 10;

mysql理解:整体合并之后只取10行,不是两条各自限制10条。

正确写法:子查询使用括号包裹

(select id,username from `user` limit 10)
union all
(select id,access_key from `app_key` limit 10);

陷阱2:子查询内order by默认无效

单独写order by不会生效,只有搭配limit时,括号内排序才会执行

-- 内部排序生效
(select id,username from `user` order by create_time desc limit 5)
union all
(select id,access_key from `app_key` order by create_time desc limit 5);

陷阱3:想要整体结果统一排序

把全部拼接结果作为子查询,外层统一order by

select * from (
    (select id,username from `user` limit 10)
    union all
    (select id,access_key from `app_key` limit 10)
) t
order by id desc;

六、经典业务场景:跨表or条件优化(实战高频)

原始问题sql(性能差、逻辑存在隐患)

select t1.id,t1.username
from `user` t1
left join `app_key` t2 on t1.id = t2.user_id
where t1.username = 'demo' or t2.access_key = 'demo_key';

这类left join + or跨表条件极易索引失效。

标准优化手段:拆分查询,union all纵向拼接

-- 场景1:匹配用户表账号
select id, username from `user` where username = 'demo'

union all

-- 场景2:匹配密钥表,关联查询用户
select t1.id, t1.username
from `user` t1
inner join `app_key` t2 on t1.id = t2.user_id
where t2.access_key = 'demo_key';

如需去重外层包distinct,每条分支独立执行,能够正常使用各自索引。

拓展:只需要查询任意一条匹配数据(短路查询)

登录、账号检索场景,找到第一条即可返回,减少扫描:

select * from (
    (select id, username from `user` where username = 'demo' limit 1)
    union all
    (select t1.id, t1.username from `user` t1
     inner join `app_key` t2 on t1.id = t2.user_id
     where t2.access_key = 'demo_key' limit 1)
) tmp limit 1;

如果第一条分支命中,数据库不需要继续执行第二条查询。

七、纵向拼接编码规范与优化建议

  1. 优先使用 union all,杜绝无条件使用 union;只有确认必须全局去重时,使用union all + distinct
  2. 不要使用select *,显式指定字段,保证结构稳定;
  3. 子查询需要限制行数,必须用括号包裹;
  4. 多条分支查询务必建立合适索引,纵向拼接不会提升单条子查询性能;
  5. 分支数量不宜过多,过多子查询可读性变差,可以考虑应用层多次查询合并;
  6. 大数据场景避免上万行结果拼接,网络传输消耗较大;
  7. 不要依靠union实现单表内部去重,单表去重直接使用distinct

八、常见误区汇总

误区1:union一定比union all简洁,少量数据无所谓

测试环境少量数据看不出差距;线上十万级结果集,临时表+排序会直接造成接口超时。

误区2:where条件写在一起,不如union拼接灵活

很多跨表or、复杂多条件检索,拆分union all是唯一能稳定走索引的方案。

误区3:子查询的字段别名全局生效

只有第一条select的别名作为最终列名,后续子查询别名会被忽略。

误区4:union all内部自动去重

不会,重复记录会完整保留,必须手动处理。

九、验证手段

使用explain分析执行计划:

  • union:可见<union>using temporaryusing filesort
  • union all:执行计划简洁,不存在全局临时表与排序

十、全文总结

  1. mysql纵向拼接依靠union / union all,作用是堆叠多行;横向合并依靠join,二者不要混淆;
  2. 性能铁律:优先 union all;需要去重采用 union all + distinct,尽量避免直接union
  3. limit、order by作用范围容易踩坑,子查询增加括号控制作用域;
  4. left join + or跨表条件慢查询,首选方案:拆分为多条查询,union all纵向拼接;
  5. 任何优化的前提:每条独立子查询本身能够正常命中索引。

日常开发牢记:纵向拼接只是结果合并手段,无法提升单条查询扫描效率,优化重心依然在每条分支sql与索引设计。

以上就是mysql中多条查询结果纵向拼接(union/union all)优化指南的详细内容,更多关于mysql纵向拼接的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com