MySQL UNION ALL:一次查询多表统计数据的高效实践
在业务开发中,常需从多个无直接关联的表中分别提取数据(如统计学生与教师的性别分布)。若采用传统子表拼接或多次请求,将大幅增加数据库交互开销。本文详解如何使用 UNION ALL 关键字进行纵向合并,配合外层聚合函数,实现单次 SQL 查询多条独立统计数据,有效减轻系统压力。
问题背景与性能瓶颈
假设我们需要在一次请求中获取“学生表中男生总数”和“教师表中男教师总数”。如果分别编写两条 SQL 语句或在应用层循环查询,会占用两次以上的连接资源,增加延迟。
传统的处理方式是将对每个子表的查询封装为临时表(别名),然后通过逗号分隔的多表连接(隐式笛卡尔积)将它们拼合。虽然只需一条 SQL,但其底层逻辑往往不够直观,且在数据量较大时可能引发性能担忧。

准备工作:创建测试数据
为了演示效果,我们构建两张基础的表:student(学生表)和 teacher(教师表)。
第1步:建立学生表结构并插入数据
目的:提供包含姓名、性别等字段的学生数据,用于后续筛选统计。
操作:创建表并插入模拟记录。
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
`birth` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
`sex` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('01', '赵雷', '1990-01-01', '男');
INSERT INTO `student` VALUES ('02', '钱电', '1990-12-21', '男');
INSERT INTO `student` VALUES ('03', '孙风', '1990-05-20', '男');
INSERT INTO `student` VALUES ('04', '李云', '1990-08-06', '男');
INSERT INTO `student` VALUES ('05', '周梅', '1991-12-01', '女');
INSERT INTO `student` VALUES ('06', '吴兰', '1992-03-01', '女');
INSERT INTO `student` VALUES ('07', '郑竹', '1989-07-01', '女');
INSERT INTO `student` VALUES ('08', '王菊', '1990-01-20', '女');
SET FOREIGN_KEY_CHECKS = 1;
第2步:建立教师表结构并插入数据
目的:提供独立的教师基础数据。
操作:创建表并插入模拟记录。
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
`sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES ('01', '张三', '男');
INSERT INTO `teacher` VALUES ('02', '李四', '女');
INSERT INTO `teacher` VALUES ('03', '王五', '男');
SET FOREIGN_KEY_CHECKS = 1;
解决方案:使用 UNION ALL 合并查询
UNION ALL 的作用是将两个或多个 SELECT 语句的结果集纵向堆叠在一起。要实现一次性查询,核心思路是构造两行数据:第一行存放学生统计数据(教师列填 0),第二行存放教师统计数据(学生列填 0)。
第3步:通过 UNION ALL 生成中间结果集
入口:SELECT 语句组合。
动作:分别统计男女学生/教师数量,并用 0 填充对方字段以保持列数一致。
关键参数:AS a, AS b 作为列别名。
预期状态:返回两行数据,每行包含两个数值。
select t.* from
(
-- 第一部分:学生表统计,b设为0
SELECT count(id) as a, 0 as b FROM student WHERE student.sex = '男'
UNION ALL
-- 第二部分:教师表统计,a设为0
SELECT 0 as a, count(id) as b FROM teacher WHERE teacher.sex = '男'
) t


第4步:外层聚合求和得出最终结果
入口:包裹上述查询的外层 SELECT。
动作:对中间结果集的 a 列和 b 列分别执行 SUM 聚合。
重要参数:SUM(t.a) 即为所有男生学生总数,SUM(t.b) 即为所有男教师总数。
预期状态:返回仅一行数据,包含两个总和值。
select sum(t.a) as "学生男生总数", sum(t.b) as "男教师总数" from
(
SELECT count(id) as a, 0 as b FROM student WHERE student.sex = '男'
UNION ALL
SELECT 0 as a, count(id) as b FROM teacher WHERE teacher.sex = '男'
) t

方案总结
相比传统的多表嵌套或应用层循环调用,使用 UNION ALL 配合 SUM 函数具有以下优势:
- 请求次数少:只需向数据库发送一个 SQL 请求即可获取多个互不关联表的统计指标。
- 逻辑清晰:各子查询独立运行,互不干扰,维护成本低。
- 性能更优:减少了网络往返时间(RTT)及数据库上下文切换开销,显著提升系统响应速度。
以上就是 MySQL 中使用 UNION ALL 进行多表联合统计的详细内容,更多关于 MySQL 优化技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













