mysql多条查询结果纵向拼接的实现
前言
在日常开发中,我们经常需要把多条独立SELECT查询的结果上下堆叠合并,也就是纵向拼接。
很多人容易混淆两个概念:
JOIN:横向拼接,增加列;UNION / UNION ALL:纵向拼接,增加行。
不少开发直接上手写UNION,遇到大数据量直接触发慢查询;同时还有LIMIT失效、排序异常、索引无法利用、跨表OR改造等一系列踩坑点。
本文系统讲解MySQL纵向拼接语法、底层差异、规范写法、高频陷阱以及线上最优实践。
一、什么是纵向拼接
横向拼接(JOIN):两张表根据关联字段左右合并,行数重组,字段增多。
纵向拼接(UNION系列):把多条查询结果上下堆叠,字段结构保持一致,行数累加。
示意图通俗理解:
查询A结果: id | name 1 | 张三 查询B结果: id | name 2 | 李四 纵向拼接后: id | name 1 | 张三 2 | 李四
二、基础语法与强制约束
纵向拼接依靠两个关键字:UNION、UNION ALL。
硬性规则(违反直接报错)
- 每条子查询列数量必须完全一致;
- 对应位置字段数据类型尽量兼容;
- 最终字段名称由第一条SELECT决定,后续子查询别名无效;
- 不推荐子查询使用
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
- 合并结果后自动全局去重;
- MySQL底层会创建临时表、执行排序比对重复;
- 执行计划大概率出现
Using temporary; Using filesort; - 性能较差,大数据量慎用。
UNION = UNION ALL + DISTINCT 全局去重
UNION ALL
- 直接原样纵向拼接,不去重、不排序;
- 无临时表、无全局排序开销;
- 性能远高于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;
如果第一条分支命中,数据库不需要继续执行第二条查询。
七、纵向拼接编码规范与优化建议
- 优先使用 UNION ALL,杜绝无条件使用 UNION;只有确认必须全局去重时,使用
UNION ALL + DISTINCT; - 不要使用
SELECT *,显式指定字段,保证结构稳定; - 子查询需要限制行数,必须用括号包裹;
- 多条分支查询务必建立合适索引,纵向拼接不会提升单条子查询性能;
- 分支数量不宜过多,过多子查询可读性变差,可以考虑应用层多次查询合并;
- 大数据场景避免上万行结果拼接,网络传输消耗较大;
- 不要依靠UNION实现单表内部去重,单表去重直接使用
DISTINCT。
八、常见误区汇总
误区1:UNION一定比UNION ALL简洁,少量数据无所谓
测试环境少量数据看不出差距;线上十万级结果集,临时表+排序会直接造成接口超时。
误区2:WHERE条件写在一起,不如UNION拼接灵活
很多跨表OR、复杂多条件检索,拆分UNION ALL是唯一能稳定走索引的方案。
误区3:子查询的字段别名全局生效
只有第一条SELECT的别名作为最终列名,后续子查询别名会被忽略。
误区4:UNION ALL内部自动去重
不会,重复记录会完整保留,必须手动处理。
九、验证手段
使用EXPLAIN分析执行计划:
- UNION:可见
<union>、Using temporary、Using filesort - UNION ALL:执行计划简洁,不存在全局临时表与排序
十、全文总结
- MySQL纵向拼接依靠
UNION / UNION ALL,作用是堆叠多行;横向合并依靠JOIN,二者不要混淆; - 性能铁律:优先 UNION ALL;需要去重采用 UNION ALL + DISTINCT,尽量避免直接UNION;
- LIMIT、ORDER BY作用范围容易踩坑,子查询增加括号控制作用域;
LEFT JOIN + OR跨表条件慢查询,首选方案:拆分为多条查询,UNION ALL纵向拼接;- 任何优化的前提:每条独立子查询本身能够正常命中索引。
日常开发牢记:纵向拼接只是结果合并手段,无法提升单条查询扫描效率,优化重心依然在每条分支SQL与索引设计。
到此这篇关于mysql多条查询结果纵向拼接的实现的文章就介绍到这了,更多相关mysql查询结果纵向拼接内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Mysql Error 1826:Duplicate foreign key&n
MySQL1826错误是由于在创建表时,外键索引名重复导致的,解决办法是在创建外键时指定不同的索引名,或修改ForeignKeyName,此问题需注意索引和外键名称的唯一性2026-05-05
MySQL报错:The server quit without updating PID file的解决思路
最近在学习mysql二进制的时候遇到了个报错,解决分享给大家,这篇文章主要给大家介绍了关于MySQL报错:The server quit without updating PID file的解决思路与方法,需要的朋友可以参考下2023-02-02


最新评论