返回顶部
首页 > 资讯 > 数据库 >一篇文章了解MySQL的group by
  • 772
分享到

一篇文章了解MySQL的group by

mysql数据库java 2023-08-18 12:08:00 772人浏览 八月长安
摘要

准备工作! 本文章Mysql使用的是5.7,引擎使用的是innodb 2. 使用的表结构(t1),字段a上有一个索引, 1. group by常用方法: group by的常规用法是配合聚合函数,利用分组信息进行统计,常见的是配合max等

准备工作!

本文章Mysql使用的是5.7,引擎使用的是innodb
2. 使用的表结构(t1),字段a上有一个索引
在这里插入图片描述

1. group by常用方法:

group by的常规用法是配合聚合函数,利用分组信息进行统计,常见的是配合max等聚合函数筛选数据后分析,以及配合having进行筛选后过滤。
聚合函数

  • count(),返回指定列中数据的个数
  • sum(),返回指定列中数据的总和
  • avg(),返回指定列中数据的平均值
  • min(),返回指定列中数据的最小值
  • max(),返回指定列中数据的最大值

示例1: 查询t1表,按照字段b进行分组,并求出分组后b字段a的总和。

SELECT  MAX(a) from t1 GROUP BY b

实例2:查询t1表,按照字段b进行分组,拿到b<100的所有数据,求出a的总和。

SELECT  MAX(a) from t1 GROUP BY b HAVING b<100

where和having区别

where子句将单个行过滤到查询结果中,而having子句将分组过滤到查询结果中 having子句中使用的列名必须出现在group by子句列表中,或包括在聚集函数中。

having子句的条件运算至少包括一个聚集函数,否则可以把查询条件移到where字句中来过滤单个行(注意聚集函数不可以用在where子句中)


2. group by语句执行流程:

我们执行以下语句

SELECT  b, count(*) as c from t1 GROUP BY b HAVING b<100

查看explain执行情况,由于b字段上没有索引,所以进行全表扫描。
在这里插入图片描述

Using temporary; 表示使用了临时表;
Using filesort ,表示需要排序。

由于字段b上没有索引,它的执行顺序是这样的

  • 创建内存临时表,表里有两个字段 b 和 c,主键是 b;
  • 对t1表进行全表扫描,并取出第一条数据,判断b是否小于100。如果b<100,就记录b的值为X,并存入临时表。
    1.如果临时表中没有主键为b的行,就插入一条记录 b,c(x,1)
    2.如果临时表中有主键为b的行,就更新主键为b的这一行,并把c的值进行加1
  • 遍历完成后,再根据字段 b做排序,得到结果集返回给客户端。

在MySQL当中排序有两种
第一种是 全字段排序 ,第二种是 rowid 排序。 具体可以通过我的这篇文章去了解一篇文章搞懂MySQL的order by


3.使用group by会有哪些问题:

我们执行以下语句

SELECT  b, count(*) as c from t1 GROUP BY b HAVING b<100

在上述中,由于b字段没有索引,索引mysql默认会对此语句进行排序。相信你也看了我的一篇文章搞懂MySQL的order by这篇文章,也了解了Mysql什么时候会用全字段排序,什么时候用 rowid 排序。

1. 使用磁盘临时文件进行排序

在此语句中,优化器使用的是全字段排序,那么使用全字段排序会有哪些问题?
在全字段排序中,它是通过sort_buffer进行排序,定义如下。

sort_buffer_size:就是 MySQL 为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。

假如我们如下SQL语句查出有1亿行,这时由于我们查询数据大小超过了定义的 临时排序文件( sort_buffer_size)的大小时,

SELECT  b, count(*) as c from t1 GROUP BY b HAVING b<100000000

那么,这时就需要使用外部排序,外部排序一般使用归并排序算法。可以这么简单理解,MySQL 将需要排序的数据分成 n份,每一份单独排序后存在这些临时文件中。然后把这n个有序文件再合并成一个有序的大文件。由于分成的的临时文件很多,就会造成排序的性能很差。


2. 查询数据超过临时文件大小(tmp_table_size)

这个例子里由于临时表只有 100 行,内存可以放得下,因此全程只使用了内存临时表。但是,内存临时表的大小是有限制的,参数 tmp_table_size 就是控制这个内存大小的,默认是 16M。接下来我把tmp_table_size大小改成1kb。

假如我们如下SQL语句查出有1亿行,这时由于我们查询数据大小超过了定义的 临时文件( tmp_table_size)的大小时。

SELECT  b, count(*) as c from t1 GROUP BY b HAVING b<100000000

那么,这时就会把内存临时表转成磁盘临时表(磁盘临时表默认使用的引擎是 InnoDB)。由于我们数据量很大,很可能这个查询需要的磁盘临时表就会占用大量的磁盘空间。


4.group by的优化方法:

我们还是以这条SQL语句为准

SELECT  b, count(*) as c from t1 GROUP BY b HAVING b<100

1. 如果你的需求并不需要对结果进行排序,那你可以在 SQL 语句末尾增加 order by null

explain SELECT  b, count(*) as c from t1 GROUP BY b HAVING b<100 ORDER BY null 

查看explain 结果在这里插入图片描述

Using temporary; 表示使用了临时表;


2. 可以对group by字段建立索引

众所周知,由于我们MySQL的InnoDB引擎使用的数据结构是B+树,而B+树相比于B树最显著的特征就是B+树叶子节点是一个有序的双向列表。既然他已经有序了,那么我们是不是可以直接不进行排序了。

我们执行以下SQL语句,并在字段b上建立索引

SELECT  b, count(*) as c from t1 GROUP BY b HAVING b<100

查看explain执行情况,没有进行排序,没有使用临时文件
在这里插入图片描述

Using index;使用了覆盖索引。
由于字段b上有索引,它的执行顺序是这样的

在这里插入图片描述

执行流程:

  • 扫描t1表的索引b,读取磁盘块1,将磁盘块加载到内存中判断50是否小于100,是就走左边,不是就走右边。

  • 扫描磁盘块2,将磁盘块加载到内存中判断判断30是否小于100,是就走左边,不是就走右边。

  • 读取磁盘块3,将磁盘块加载到内存中判断判断20是否小100,是就走左边,不是就走右边。

  • 读取磁盘块4也就是叶子节点,它是一个有序的链表。从键值10开始向后遍历筛选所有符合筛选条件的数据,并将符合筛选条件的data值数据缓存到结果集。(因为是双向有序的,所以会依次读取,并不需要回到父节点。因此当读取到20后会直接读取磁盘块5)
    1.当碰到第一个 10 的时候,结果集里的第一行就是 (10,1);
    2.当碰到第二个 10 的时候,已经知道累积了 1 个 10,修改结果集里的第一行为(10,2);

  • 当依次读取导磁盘块12后,将磁盘块加载到内存中判断100是否小于100,不是;就不需再向后查找,查询终止。将结果集返回给用户。

因此当我们扫描到整个输入的数据结束,就可以拿到 group by 的结果,不需要临时表,也不需要再额外排序


3. group by字段无法建立索引时

如果可以通过加索引来完成 group by 逻辑就再好不过了。但是,如果碰上不适合创建索引的场景,我们还是要老老实实做排序的。那么,这时候的 group by 要怎么优化呢?

如果我们明明知道,一个 group by语句中需要放到临时表上的数据量特别大,却还是要按照“先放到内存临时表,插入一部分数据后,发现内存临时表不够用了再转成磁盘临时表”,这样看上去就有点儿傻。

我们执行以下SQL语句,并使用 SQL_BIG_RESULT(SQL_BIG_RESULT告诉mysql的分组语句必须使用磁盘临时表)

SELECT  SQL_BIG_RESULT b, count(*) as c from t1 GROUP BY b HAVING b<100

查看explain执行情况
在这里插入图片描述
Using filesort 表示需要排序。

执行流程:

  • .初始化 sort_buffer,确定放入一个整型字段,记为 b;
  • . 扫描表 t1 ,依次取出里面b<100的值, 将b的值存入 sort_buffer 中;
  • . 扫描完成后,对 sort_buffer 的字段 b 做排序(如果 sort_buffer 内存不够用,就会利用磁盘临时文件辅助排序);
  • . 排序完成后,就得到了一个有序数组

在根据有序数组,得到数组里面的不同值,以及每个值的出现次数。


5. MySQL8.0之后版本的group by

我们还是以这条SQL语句为准(MySQL版本8.0.26)

SELECT  b, count(*) as c from t1 GROUP BY b HAVING b<100

查看explain执行情况
在这里插入图片描述
Using temporary; 表示使用了临时表;

group by 在 MySQL5.7 版本会自动排序,但是在MySQL8 .0之后版本就去掉了自动排序功能。


6.总结

1.如果对 group by 语句的结果没有排序要求,要在语句后面加 order by null;

2.尽量让 group by 过程用上表的索引,确认方法是 explain 结果里没有 Using temporary 和 Using filesort;

3.如果 group by 需要统计的数据量不大,尽量只使用内存临时表;也可以通过适当调大 tmp_table_size 参数,来避免用到磁盘临时表;

4.如果数据量实在太大,使用 SQL_BIG_RESULT 这个提示,来告诉优化器直接使用排序算法得到 group by 的结果。

5.group by 在 MySQL5.7 版本会自动排序,但是在MySQL8 .0之后版本就去掉了排序功能。


在这里插入图片描述

今晚我支持总监,法国冲冲冲!!!

来源地址:https://blog.csdn.net/qq_48157004/article/details/128067845

您可能感兴趣的文档:

--结束END--

本文标题: 一篇文章了解MySQL的group by

本文链接: https://lsjlt.com/news/373983.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 一篇文章了解MySQL的group by
    准备工作! 本文章MySQL使用的是5.7,引擎使用的是innodb 2. 使用的表结构(t1),字段a上有一个索引, 1. group by常用方法: group by的常规用法是配合聚合函数,利用分组信息进行统计,常见的是配合max等...
    99+
    2023-08-18
    mysql 数据库 java
  • 一篇文章带你了解清楚Mysql 锁
    一丶为什么数据库需要锁 数据库锁设计的初衷是处理并发问题。作为多用户共享 的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则。而锁就是用来实 现这些访问规则的重要数据结构。 根据加锁的范围,mysql 里面...
    99+
    2022-11-29
    mysql锁机制 mysql锁机制应用场景 mysql锁表和解锁语句
  • 一篇文章带你了解MySQL索引下推
    目录前言SELECT 语句执行过程什么是索引下推?动手实验:索引下推限制拓展:虚拟列总结前言 本文围绕这三个话题来学习索引下推: SELECT 语句执行过程什么是索引下推?索引下推限制 SELECT 语句执行过...
    99+
    2024-04-02
  • 一篇文章带你深入了解Mysql触发器
    目录1.对SC表进行插入或修改时,如果考试成绩不在0-100范围内时,则撤销插入或修改操作。2.对SC表进行插入时,如果学生的选课总学分超过30,则报错并撤销插入。3.对SC表进行修...
    99+
    2024-04-02
  • 一篇文章带你了解MySQL数据库基础
    目录1. 数据库概念1.1 数据库是干嘛的?1.2 数据库和数据结构是啥关系?1. 数据库是一个软件/程序1.3 两种类型的数据库2. MySQL数据库2.1 MySQL数据...
    99+
    2024-04-02
  • 一篇文章带你了解Python中的类
    目录1、类的定义2、创建对象3、继承总结1、类的定义 创建一个rectangle.py文件,并在该文件中定义一个Rectangle类。在该类中,__init__表示构造方法。其中,s...
    99+
    2024-04-02
  • 一篇文章了解c++中的new和delete
    目录new expressiondelete expressionnew[]和new()new[]和delete[]new的内存分布placement newnew失败处理捕捉异常禁...
    99+
    2024-04-02
  • 一篇文章带你了解Spring AOP 的注解
    目录1、xml 的方式实现 AOP①、接口 UserService②、实现类 UserServiceImpl③、切面类,也就是通知类 MyAspect④、AOP配置文件 applic...
    99+
    2024-04-02
  • 一篇文章带你了解初始Spring
    目录为什么要使用SpringSpring概述Spring容器使用流程1.启动容器2.完成bean的初始化3.注册bean到容器中4.装配bean的属性bean的注册bean属性注入总...
    99+
    2024-04-02
  • 一篇文章带你了解JavaScript-对象
    目录创建对象对象直接量通过new创建对象原型Object.create()属性的查询和设置继承属性访问错误删除属性检测属性序列化对象总结创建对象 对象直接量 对象直接量是由若干名/值...
    99+
    2024-04-02
  • 一篇文章带你了解JavaScript-语句
    目录表达式语句复合语句和空语句复合语句空语句声明语句varfunction条件语句ifif/elseelse ifswitch循环whiledo/whileforfor/in跳转标签...
    99+
    2024-04-02
  • 一篇文章带你了解XGBoost算法
    目录1. 什么是XGBoost1.1 XGBoost树的定义1.2 正则项:树的复杂度1.3 树该怎么长1.4 如何停止树的循环生成2. XGBoost与GBDT有什么不同3. 为什...
    99+
    2024-04-02
  • 一篇文章带你了解Java Stream流
    目录一、Stream流引入现有一个需求:1.用常规方法解决需求2.用Stream流操作集合,获取流,过滤操作,打印输出二、Stream流的格式三、获取流四、Stream流的常用方法方...
    99+
    2024-04-02
  • 一篇文章带你了解Java SpringBoot Nacos
    目录1、什么是Nacos 1.1与eureka对比1.2与zookeeper对比1.3与springcloud config 对比 2、Spring Cloud Alibaba 套件...
    99+
    2024-04-02
  • 一篇文章了解SQL注入漏洞
    目录SQL注入漏洞原理SQL注入内容注入条件SQL注释符与注入流程SQL注入分类SQLMap 分类接受请求类型区分注入数据类型的区分SQL注入思路手工注入思路SQL 详细注入过程总结...
    99+
    2024-04-02
  • 一篇文章带你了解vue路由
    目录概念Vue Router简介Vue Router的特性Vue Router的使用步骤分类嵌套路由动态路由命名路由编程式导航总结概念 路由的本质就是一种对应关系,比如说我们在url...
    99+
    2024-04-02
  • 一篇文章带你了解jQuery动画
    目录1.控制元素的显示与隐藏 show() hide()2.控制元素的透明度 fadeIn() fadeOut()3:控制元素的高度 slideUp() slideDown()总结 ...
    99+
    2024-04-02
  • 一篇文章带你了解JavaScript的解构赋值
    目录1. 什么是解构赋值 ?2. 数组的解构赋值2.1) 数组解构赋值的默认值2.2) 数组解构赋值的应用类数组中的应用交换变量的值3. 对象的解构赋值...
    99+
    2024-04-02
  • 一篇文章带你了解C++的KMP算法
    目录KMP算法步骤1:先计算子串中的前后缀数组NextC++代码:步骤2:查找子串在母串中出现的位置。总结KMP算法 KMP算法作用:字符串匹配 例如母串S = “aaagoogle...
    99+
    2024-04-02
  • 一篇文章带你了解C++中的异常
    目录异常抛出异常基本操作自定义的异常类栈解旋异常接口声明异常变量的生命周期异常的多态c++的标准异常库编写自己的异常类总结异常 在c语言中,对错误的处理总是两种方法: 1,使用整型的...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作