SQL进阶之旅 Day 12:分组聚合与HAVING高效应用

news2025/6/5 15:01:15

【SQL进阶之旅 Day 12】分组聚合与HAVING高效应用

在SQL的世界里,分组聚合(Grouping and Aggregation)是处理大规模数据集时最常用的技术之一。它允许我们将数据按照某些列进行分类,并对每个分类进行统计计算。而 HAVING 子句则是对这些聚合结果进行进一步筛选的强大工具。

本篇文章将带你深入理解 GROUP BYHAVING 的工作原理、适用场景以及性能优化策略,并通过完整的 SQL 示例展示其强大功能,同时涵盖 MySQL 和 PostgreSQL 两大主流数据库的差异及最佳实践。

理论基础:分组聚合与HAVING详解

什么是分组聚合?

分组聚合是指将数据按一个或多个字段进行分组,并对每组数据进行聚合计算(如求和、计数、平均值等)。常见的聚合函数包括:

  • COUNT():计数
  • SUM():求和
  • AVG():平均值
  • MIN():最小值
  • MAX():最大值

例如,假设我们有一个销售订单表 orders,我们可以按产品类别分组,然后统计每类产品的总销售额。

HAVING的作用

HAVING 子句用于对分组后的结果进行过滤,类似于 WHERE 对原始数据行的过滤。不同的是,WHERE 是在分组前进行过滤,而 HAVING 是在分组后对聚合结果进行过滤。

例如,如果我们只想查看总销售额大于 10000 的产品类别,就可以使用 HAVING SUM(total) > 10000

GROUP BY 和 HAVING 的语法结构

SELECT column1, aggregate_function(column2)
FROM table_name
[WHERE condition]
GROUP BY column1
[HAVING aggregate_condition];

适用场景:何时使用分组聚合与HAVING?

以下是一些典型业务场景:

  1. 统计报表生成:如月度销售额汇总、用户活跃度排行。
  2. 异常检测:找出某类数据中平均值异常高的记录。
  3. 客户行为分析:分析哪些用户群体购买了超过一定金额的商品。
  4. 库存管理:统计每种商品的库存总量,并筛选出库存不足的产品。
  5. 日志分析:按错误类型分组统计日志数量。

代码实践:GROUP BY 与 HAVING 使用示例

示例一:基本的GROUP BY 分组统计

-- 统计每个类别的总销售额
SELECT category, SUM(amount) AS total_sales
FROM orders
GROUP BY category;

示例二:使用HAVING 过滤分组结果

-- 找出总销售额超过10000的类别
SELECT category, SUM(amount) AS total_sales
FROM orders
GROUP BY category
HAVING SUM(amount) > 10000;

示例三:多列分组 + 多条件HAVING

-- 按地区和年份分组,筛选出年销售额超过10万且订单数超过100的记录
SELECT region, EXTRACT(YEAR FROM order_date) AS year,
       SUM(amount) AS total_sales,
       COUNT(*) AS order_count
FROM orders
GROUP BY region, EXTRACT(YEAR FROM order_date)
HAVING SUM(amount) > 100000 AND COUNT(*) > 100;

示例四:使用HAVING 与 CASE WHEN 结合

-- 按用户ID分组,统计高价值客户(至少有5笔订单,且总消费超过5000)
SELECT user_id,
       COUNT(*) AS order_count,
       SUM(amount) AS total_spent
FROM orders
GROUP BY user_id
HAVING 
    COUNT(*) >= 5
    AND SUM(amount) > 5000;

示例五:MySQL vs PostgreSQL 差异演示

MySQL 中默认允许 SELECT 非聚合字段不包含在 GROUP BY 中(依赖于 sql_mode)
-- 在MySQL中可能可以运行(取决于sql_mode设置)
SELECT category, product_name, SUM(amount) AS total_sales
FROM orders
GROUP BY category;

⚠️ 注意:虽然MySQL在某些配置下允许这种写法,但语义上并不清晰,推荐始终将非聚合字段放入 GROUP BY

PostgreSQL 要求所有非聚合字段必须出现在 GROUP BY 子句中
-- PostgreSQL 必须这样写
SELECT category, product_name, SUM(amount) AS total_sales
FROM orders
GROUP BY category, product_name;

执行原理:数据库引擎如何处理分组聚合?

查询执行流程概述

  1. FROM:从指定表中读取原始数据。
  2. WHERE:对原始数据进行初步过滤。
  3. GROUP BY:根据指定列进行分组,形成临时中间表。
  4. HAVING:对分组后的结果进行过滤。
  5. SELECT:选择最终输出字段。
  6. ORDER BY:排序输出结果。

内部机制分析

  • GROUP BY 实际上是一个“归并”操作,数据库会为每个分组键创建哈希桶或排序树。
  • 如果数据量较大,可能会触发磁盘排序(sort merge),影响性能。
  • HAVING 条件通常在内存中完成,但如果数据量大,也可能涉及外部存储。
  • 若使用索引,可以加速 GROUP BY 的执行,尤其是当分组字段上有索引时。

执行计划分析(以MySQL为例)

EXPLAIN SELECT category, SUM(amount) AS total_sales
FROM orders
GROUP BY category
HAVING total_sales > 10000;
idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEordersALLNULLNULLNULLNULL1000Using temporary; Using filesort

可以看到,MySQL内部使用了 Using temporaryUsing filesort,说明进行了排序和临时表操作,性能较低。可以通过添加索引来优化。

性能测试:GROUP BY 与 HAVING 性能对比

我们使用两个不同的查询方式来比较性能差异。

测试环境

  • 数据库:MySQL 8.0 / PostgreSQL 15
  • 表名:orders(共100万条记录)
  • 字段:order_id, user_id, amount, category, order_date

测试一:简单分组 vs 带HAVING 条件

查询类型平均耗时(MySQL)平均耗时(PostgreSQL)
简单GROUP BY120ms90ms
GROUP BY + HAVING150ms110ms

结论:HAVING 对性能有一定影响,但在合理范围内,主要瓶颈在于 GROUP BY 自身的排序和聚合操作。

测试二:是否使用索引

我们在 category 上建立索引:

CREATE INDEX idx_category ON orders(category);
查询类型未使用索引使用索引
GROUP BY120ms40ms
GROUP BY + HAVING150ms55ms

结果显示,使用索引后性能显著提升,建议在频繁分组的字段上建立索引。

最佳实践:如何高效使用GROUP BY 与 HAVING

✅ 推荐做法

  1. 尽量减少分组字段数量,避免不必要的复杂分组。
  2. 在经常分组的字段上建立索引,特别是组合分组字段。
  3. 优先使用聚合函数别名进行 HAVING 条件判断,增强可读性。
  4. 避免在 HAVING 中使用复杂表达式,可能导致无法使用索引。
  5. 在 PostgreSQL 中确保 SELECT 中所有非聚合字段都出现在 GROUP BY 中
  6. 合理控制返回的数据量,避免大量数据传输。

❌ 不推荐做法

  1. 不要滥用 GROUP BY,比如对主键字段分组毫无意义。
  2. 不要在 HAVING 中使用 WHERE 应该完成的条件,应提前在 WHERE 中过滤。
  3. 不要忽略执行计划,盲目编写查询可能导致性能问题。

案例分析:电商订单分析系统中的分组聚合优化

问题描述

某电商平台每天产生数十万条订单数据,运营团队希望分析哪些城市在过去一个月内下单用户数超过100人,并且平均订单金额高于500元。

初始查询(效率低下)

SELECT city, COUNT(DISTINCT user_id) AS user_count, AVG(amount) AS avg_amount
FROM orders
WHERE order_date BETWEEN '2023-09-01' AND '2023-09-30'
GROUP BY city
HAVING user_count > 100 AND avg_amount > 500;

优化步骤

  1. 添加复合索引(order_date, city) 提高 WHERE + GROUP BY 效率。
  2. 改用物化视图缓存高频分组结果
  3. 拆分为两步查询:先过滤日期范围,再进行分组。

优化后查询

-- 第一步:过滤时间范围
CREATE TEMPORARY TABLE temp_orders AS
SELECT * FROM orders
WHERE order_date BETWEEN '2023-09-01' AND '2023-09-30';

-- 第二步:分组聚合
SELECT city,
       COUNT(DISTINCT user_id) AS user_count,
       AVG(amount) AS avg_amount
FROM temp_orders
GROUP BY city
HAVING user_count > 100 AND avg_amount > 500;

优化效果

查询类型优化前优化后
执行时间1.2s300ms

通过临时表 + 索引优化,性能提升了近4倍。

总结

今天的学习内容涵盖了 SQL 中最重要的分组聚合技术——GROUP BYHAVING,我们详细介绍了它们的理论基础、适用场景、代码实现、执行原理、性能测试以及最佳实践。通过实际案例分析展示了如何在真实项目中运用这些知识解决问题。

核心技能总结

  • 掌握 GROUP BY 的分组逻辑与使用技巧
  • 理解 HAVING 与 WHERE 的区别与联系
  • 能够编写高效的分组聚合查询语句
  • 了解不同数据库(MySQL/PostgreSQL)在分组聚合上的差异
  • 熟悉执行计划分析方法,优化分组查询性能

应用到实际工作中

  • 用于生成各类统计报表、监控指标
  • 在数据清洗和预处理阶段进行数据分组分析
  • 用于用户行为分析、销售统计、库存管理等场景

下期预告

明天我们将进入【Day 13】CTE 与递归查询技术,学习如何使用公共表表达式(CTE)简化复杂查询,并掌握递归查询(WITH RECURSIVE)在树形结构数据中的应用。敬请期待!

参考资料

  1. MySQL官方文档 - GROUP BY
  2. PostgreSQL官方文档 - GROUP BY
  3. SQL Performance Explained - Markus Winand
  4. 高性能MySQL - 第4版
  5. SQL必知必会 - Ben Forta

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2397268.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Python绘制节日祝福——以端午节和儿童节为例

端午节 端午节总算是回家了,感觉时间过得真快,马上就毕业了,用Python弄了一个端午节元素的界面,虽然有点不像,祝大家端午安康。端午节粽子(python)_python画粽子-CSDN博客https://blog.csdn.net…

C#项目07-二维数组的随机创建

实现需求 创建二维数组,数组的列和宽为随机,数组内的数也是随机 知识点 1、Random类 Public Random rd new Random(); int Num_Int rd.Next(1, 100);2、数组上下限。 //定义数组 int[] G_Array new int[1,2,3,4];//一维数组 int[,] G_Array_T …

光伏功率预测 | LSTM多变量单步光伏功率预测(Matlab完整源码和数据)

光伏功率预测 | MATLAB实现基于LSTM长短期记忆神经网络的光伏功率预测 目录 光伏功率预测 | MATLAB实现基于LSTM长短期记忆神经网络的光伏功率预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 光伏功率预测 | LSTM多变量单步光伏功率预测(Matlab完整源码和…

一步一步配置 Ubuntu Server 的 NodeJS 服务器详细实录——3. 服务器软件更新,以及常用软件安装

前言 前面,我们已经 安装好了 Ubuntu 服务器系统,并且 配置好了 ssh 免密登录服务器 ,现在,我们要来进一步的设置服务器。 那么,本文,就是进行服务器的系统更新,以及常用软件的安装 调整 Ubu…

PyTorch 入门学习笔记

一、简介 PyTorch 是由 Meta(原 Facebook) 开源的深度学习框架。其前身 Torch 是一个基于 LuaJIT 的科学计算框架,核心功能是提供高效的张量(Tensor)操作和神经网络支持。由于 Lua 语言的生态限制,Torch 逐…

pycharm生成图片

文章目录 图片例子生成图片并储存,设置中文字体支持两条线绘制散点图和直方图绘制条形图(bar)绘制条形图(横着的)(plt.barh)分组的条形图 颜色和线条风格1. **颜色字符 (color)**其他颜色指定方…

Android 云手机横屏模式下真机键盘遮挡输入框问题处理

一、背景 打开横屏应用,点击云机EditText输入框,输入框被键盘遮挡,如下图: 未打开键盘状态: 点击第二个输入框,键盘遮挡了输入框: 二、解决方案(推荐第三中方案,博主采用的也是第三种方案) 博主这里整理了三种方案:…

Axure设计案例——科技感对比柱状图

想让数据对比展示摆脱平淡无奇,瞬间抓住观众的眼球吗?那就来看看这个Axure设计的科技感对比柱状图案例!科技感设计风格运用独特元素打破传统对比柱状图的常规,营造出一种极具冲击力的视觉氛围。每一组柱状体都仿佛是科技战场上的士…

FPGA仿真中阻塞赋值(=)和非阻塞赋值(<=)区别

FPGA仿真中阻塞赋值和非阻塞赋值的区别 单独仿真小模块对但将小模块加入整个工程仿真不对就有可能是没有注意到仿真中阻塞赋值和非阻塞赋值的区别 目录 前言 一、简介 二、设计实例 三、仿真实例 1、仿真用非阻塞赋值 2、仿真用阻塞赋值 总结 前言 网上很多人介绍verilo…

LabVIEW轴角编码器自动检测

LabVIEW 开发轴角编码器自动检测系统,针对指控系统中高故障率的轴角编码器性能检测需求,通过模块化硬件架构与软件设计,实现编码器运转状态模拟、扭矩 / 转速实时监测、19 位并行编码采集译码、数据自动分析及报告生成等功能,解决…

MySQL数据库从0到1

目录 数据库概述 基本命令 查询命令 函数 表的操作 增删改数据和表结构 约束 事务 索引 视图 触发器 存储过程和函数 三范式 数据库概述 SQL语句的分类: DQL:查询语句,凡是select语句都是DQL。 DML:insert,delete,up…

WiFi万能钥匙鲲鹏服务器部署 TiDB 集群实战指南

作者: TiDBer_yangxi 原文来源: https://tidb.net/blog/15a234d0 一、环境准备 1. 硬件要求 服务器架构 :鲲鹏服务器(ARM架构),TiDB 官方明确支持 ARM 架构服务器部署 推荐配置 (生产环…

Vue 核心技术与实战智慧商城项目Day08-10

温馨提示:这个黑马的视频在b占可以找到,里面有完整的教学过程 然后这个项目有完整的代码,我已经上传了,如果审核成功大家就可以看了,但是需要审核多久我也不是很确定 1.项目演示 2. 项目收获 3. 创建项目 4. 调整初始化…

TCP/IP协议精华总结pdf分享

hi ,大家好,应小伙伴们的要求,上次分享了个人的一些学习和职场经验,其中网络协议PDF文档是我之前学习协议的时候总结一些精华知识,网络属于基本功,是互联网必备知识,我深信掌握好核心20%知识&am…

⚡️ Linux grep 命令参数详解

⚡️ Linux grep 用法及参数详解 📘 1. grep 简介 grep 是 Linux/Unix 系统中用于文本搜索的命令,其全称为 Global Regular Expression Print,意为全局正则表达式打印器。 它根据给定的 模式(pattern) 对文件或标准…

2025年第三届CCF·夜莺开源创新论坛通知

点击蓝字 关注我们 CCF Opensource Development Committee 01 大会简介 由中国计算机学会主办、CCF开源发展委员会及夜莺开源社区承办的第三届CCF夜莺开源创新论坛拟于2025年7月4日在北京召开。本次论坛以“AI 加速可观测”为主题,汇聚了开源夜莺核心开发团队&#…

GMDCMonitor企业版功能分享0602

企业版包含了拓扑中心、签退中心、知识库、通知渠道配置、平台自定义,这5个功能 1)拓扑中心 拓扑中心绘制的时候需要注意2点: 1)要先选择 “矩形区域” 或 “圆形区域” 来添加各个背景区域,同时录入区域尺寸&#x…

Warm-Flow发布1.7.3 端午节(设计器流和流程图大升级)

Warm-Flow发布1.7.3 端午节(设计器流和流程图大升级) 更新内容项目介绍功能思维导图演示地址官网Warm-Flow视频 更新内容 [feat] 新版流程图通过前端渲染[perf] 美化流程设计器ui[feat] 办理人权限处理器,新增办理人转换接口,比如…

【存储基础】SAN存储基础知识

文章目录 1. 什么是SAN存储?2. SAN存储组网架构3. SAN存储的主要协议SCSI光纤通道(FC)协议iSCSIFCoENVMe-oFIB 4. SAN存储的关键技术Thin Provision:LUN空间按需分配Tier:分级存储Cache:缓存机制QoS&#x…

2025年ESWA SCI1区TOP,改进成吉思汗鲨鱼算法MGKSO+肝癌疾病预测,深度解析+性能实测

1.摘要 本文针对肝癌(HCC)早期诊断难题,提出了一种基于改进成吉思汗鲨鱼优化算法(MGKSO)的计算机辅助诊断系统。由于HCC在早期症状不明显且涉及高维复杂数据,传统机器学习方法易受噪声和冗余特征干扰。为提…