group by 执行顺序

后面也会持续更新,学到新东西会在其中补充。

建议按顺序食用,欢迎批评或者交流!

缺什么东西欢迎评论!我都会及时修改的!

感谢各位大佬写的文章让我学到很多东西!只是在各位大佬的基础加了我自己的思路!

参考文献

MySQL——GROUP BY详解与优化在 `MySQL` 中,`GROUP BY`用于将具有指定列中相同值的行分组在一 - 掘金

看一遍就理解:group by 详解大家好,我是捡田螺的小男孩。 日常开发中,我们经常会使用到group by。亲爱的小 - 掘金

SQL中distinct的用法 - Rain Man - 博客园

神奇的 SQL 之层级 → 为什么 GROUP BY 之后不能直接引用原表中的列为什么 GROUP BY 之后不能直接引 - 掘金

墙裂推荐! 

3s->30ms!MySQL 生产环境 GROUP BY 优化实践MySQL 生产环境 GROUP BY 优化实践,执行 - 掘金

测试环境

MySql5.7、MySql9.0.4、Pg15

group by 和 distinct

开始前我们需要彻底了解group by 和 distinct作用

检索并列出已订购产品的清单_牛客题霸_牛客网

这个题有两种解法

// 1. 去重
select distinct prod_id from OrderItems
// 2. 分组
select prod_id from OrderItems group by prod_id

测试一下自己是否真正明白

 注意:distinct必须放在开头

pgsql中distinct与distinct on的用法

postgres=# select distinct on(id,name) id,name from test;id | name
----+------1 |    11 |    22 |    22 |    33 |    33 |    44 |    34 |    4
(8 rows)
postgres=# select distinct id,name from test;id | name
----+------1 |    12 |    23 |    44 |    32 |    33 |    34 |    41 |    2
(8 rows)select distinct id,name from test = select distinct on(id,name) id,name from test

先暂时介绍一下distinct毕竟主题是group by 

标准的错误,经典的零分

ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.Orders.cust_id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

 是由于默认的 MySQL 配置中 `sql_mode` 配置了 `only_full_group_by`,需要 `GROUP BY` 中包含所有 在 SELECT 中出现的字段。

第一种解决方案:

 第二种解决方案:any_value():将分到同一组的数据里第一条数据的指定列值作为返回数据

第三种解决方案:group_concat():将分到同一组的数据默认用逗号隔开作为返回数据

偷偷排序是吧

 在MySQL 5.7中,GROUP BY 默认隐式排序,按GROUP BY列按升序排序。如果不想在执行 GROUP BY 时执行排序的开销,可以禁用排序:

group by order by null

 group by执行流程

select age,count(age) from staff where name='小李' group by age;

 没有排序?那就排个序看看咋回事!

select age,count(age) from staff where name='小李' group by age order by age;

临时表

临时表大小为16M,参数 tmp_table_size 表示临时表内存大小。内存临时表使用的是memory引擎。

mysql> show  variables like '%tmp_table_size%';
+----------------+----------+
| Variable_name  | Value    |
+----------------+----------+
| tmp_table_size | 16777216 |
+----------------+----------+
1 row in set (0.03 sec)

如果临时表大小超过了tmp_table_size, 那么内存临时表就会转成磁盘临时表

mysql> show status like '%Created_tmp%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 3     |
| Created_tmp_files       | 6     |
| Created_tmp_tables      | 17    |
+-------------------------+-------+
3 rows in set (0.02 sec)

Created_tmp_disk_tables:在磁盘上创建内部临时表时, 服务器递增此值

Created_tmp_files:显示了MySQL服务器为存储临时数据而创建的临时文件的数量。

Created_tmp_tables:在内存中创建内部临时表时或在磁盘,服务器将递增此值。

一般理想配置
Created_tmp_disk_tables / Created_tmp_tables * 100% <= 25%                    

松散索引扫描(Loose Index Scan)

测试环境:

CREATE TABLE t2 (id INT AUTO_INCREMENT,c1 CHAR(64) NOT NULL,c2 CHAR(64) NOT NULL,c3 CHAR(64) NOT NULL,c4 CHAR(64) NOT NULL,PRIMARY KEY(id),KEY c1_c2_c3_idx (c1, c2,c3)
) ENGINE=INNODB;INSERT INTO t2 VALUES (null,'a','b','a','a'), (null,'a','b','a','a'),(null,'a','c','a','a'), (null,'a','c','a','a'),(null,'a','d','b','b'), (null,'a','b','b','b'),(null,'d','b','c','c'), (null,'e','b','c','c'),(null,'f','c','d','d'), (null,'k','c','d','d'),(null,'y','d','y','y'), (null,'f','b','f','y'),(null,'a','b','a','a'), (null,'a','b','a','a'),(null,'a','c','a','a'), (null,'a','c','a','a'),(null,'a','d','b','b'), (null,'a','b','b','b'),(null,'d','b','c','c'), (null,'e','b','c','c'),(null,'f','c','d','d'), (null,'k','c','d','d'),(null,'y','d','y','y'), (null,'f','b','f','y');  -- 收集统计信息,否则可能影响测试
ANALYZE TABLE t2;
  • 不需要扫描所有的索引,根据分组前缀(GROUY BY 的字段)跳跃扫描部分
  • Extra: Using index for group-by
mysql> explain SELECT c1,MIN(c2) FROM t2 GROUP BY c1;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t2    | NULL       | range | c1_c2_c3_idx  | c1_c2_c3_idx | 256     | NULL |    7 |   100.00 | Using index for group-by |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.01 sec)

 执行流程是这样的:

 注意:如果 SQL 语句中既有 1-2 个 min\max,也有 1-3 个 count(distinct)\sum(distinct)\avg(distinct) 时,无法用到 Loose index;两组分别出现的时候才可能会用到。

使用到 Loose Index Scan 其他必要条件:

  • 查询基于一个表。
  • GROUP BY 的字段满足索引的最左匹配原则。
  • 聚合函数使用的列,必须包含在索引上;且使用多个聚合函数时,必须使用相同的字段,且 GROUP BY 字段+聚合函数字段也必须满足最左匹配原则。
  • 索引中字段必须是全字段索引,而不能是前缀索引,例如 INDEX(c1(10))

练习可以看这个:

3s->30ms!MySQL 生产环境 GROUP BY 优化实践MySQL 生产环境 GROUP BY 优化实践,执行 - 掘金

 我觉得还是得画图来理解!

待续: 

SELECT c1,c2,c3,MAX(id) FROM t2 GROUP BY c1,c2,c3;

SELECT c1, c2 FROM t2 WHERE c3 = 'd' GROUP BY c1, c2;

紧凑索引扫描(Tight Index Scan)

  • 需要扫描范围或全部的索引
  • Extra: Using index

两种算法结合

对于统计类 AGG(DISTINCT) 即 SUM|COUNT|AVG(distinct),可能会出现使用松散索引扫描(Loose Index Scan)成本大于紧凑索引扫描(Tight Index Scan)的情况。

两种方式在引擎层主要包含的成本:

  • Loose Index Scan
    • 读取分组的第一条记录,得到分组前缀(group by age,name)age,name就是分组前缀。
    • 根据分组前缀读取分组的第一条或最后一条记录返回给 SERVER 层
  • Tight Index Scan
    • 从 ENGINE 层读取数据,返回给 SERVER 层
    • SERVER 层判断是否符合 WHERE 条件的记录,并根据聚合函数进行处理

可以看到,对于 ENGINE 层的访问,Loose Index Scan 的成本有可能会高于 Tight Index Scan,且在 MySQL 中,引擎层读取数据页的成本常数是 1,SERVER 层判断一条记录的成本常数是 0.2。

INSERT INTO t2 VALUES (null,'a','b','a','a'), (null,'a','b','a','a'),(null,'k','c','a','a'), (null,'k','g','a','a'),(null,'a','d','b','b'), (null,'a','b','b','b'),(null,'d','b','c','c'), (null,'e','b','c','c'),(null,'f','c','d','d'), (null,'k','c','d','d'),(null,'y','d','y','y'), (null,'f','b','f','y'),(null,'j','b','a','a'), (null,'m','b','a','a'),(null,'z','c','a','a'), (null,'t','c','a','a'),(null,'x','d','b','b'), (null,'x','b','b','b'),(null,'d','b','c','c'), (null,'e','b','c','c'),(null,'f','c','d','d'), (null,'k','c','d','d'),(null,'y','d','y','y'), (null,'f','b','f','y'); 
mysql> explain select count(distinct c1,c2) from t2;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra                               |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------------------------------+
|  1 | SIMPLE      | t2    | NULL       | range | c1_c2_c3_idx  | c1_c2_c3_idx | 512     | NULL |   25 |   100.00 | Using index for group-by (scanning) |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------------------------------+
1 row in set, 1 warning (0.00 sec)

执行顺序是这样的:

对于 GROUP BY 可以使用索引进行优化,Loose Index Scan 相对于 Tight Index Scan 在一些情况下可以大大减少扫描的行数,使用 Loose Index Scan 时,Extra: Using index for group-by。

在 Loose Index Scan 的成本大于 Tight Index Scan 的一些情况下,可以尝试用到两者的结合的方式,Extra: Using index for group-by (scanning)

Loose Index Scan 更适用于分组内重复值相对较多,分组个数相对较少的情况。

优化

group by 后面的字段加索引

说白了就是覆盖索引

 

没有生成临时表,直接走索引就返回数据了!

order by null 不用排序

尽量只使用内存临时表

调大tmp_table_size参数

总结

所有结论都需要反复测试!如果有错误欢迎指正!一起努力!

如果喜欢的话,请点个赞吧就算鼓励我一下!

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

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

相关文章

通过爬虫方式实现视频号助手发布视频

1、将真实的cookie贴到解压后目录中cookie.txt文件里,修改python代码里的user_agent和video_path, cover_path等变量的值,最后运行python脚本即可; 2、运行之前根据import提示安装一些常见依赖,比如requests等; 3、2025年1月份最新版; 代码如下: import json import…

Docker入门常用命令总结

1.从远程仓库拉取一个纯净的镜像 docker pull docker .io/centos 2.创建并进入容器&#xff08;左外右内&#xff09; docker run --name xxx -dit 镜像id&#xff08;镜像名称:Tag&#xff09; /bin/bash 【参数必须放在镜像ID之前】 -i 让Docker分配一个伪终端&#xff0c;并…

初学stm32 --- FSMC驱动LCD屏

目录 FSMC简介 FSMC框图介绍 FSMC通信引脚介绍 FSMC_NWE 的作用 FSMC_NWE 的时序关系 FSMC_NOE 的含义 FSMC_NOE 的典型用途 FSMC_NOE 的时序关系 使用FSMC驱动LCD FSMC时序介绍 时序特性中的 OE ILI9341重点时序&#xff1a; FSMC地址映射 HADDR与FSMC_A关系 LCD的…

CSS系列(47)-- Animation Timeline详解

前端技术探索系列&#xff1a;CSS Animation Timeline详解 ⏱️ 致读者&#xff1a;探索动画时间线的艺术 &#x1f44b; 前端开发者们&#xff0c; 今天我们将深入探讨 CSS Animation Timeline&#xff0c;这个强大的动画控制特性。 基础概念 &#x1f680; 时间线定义 …

Nginx - 整合lua 实现对POST请求的参数拦截校验(不使用Openresty)

文章目录 概述步骤 1: 安装 Nginx 和 Lua 模块步骤 2: 创建 Lua 脚本用于参数校验步骤 3: 配置 Nginx 使用 Lua 脚本写法二&#xff1a; 状态码写法三 &#xff1a; 返回自定义JSON复杂的正则校验 步骤 4: 测试和验证ngx.HTTP_* 枚举值 概述 一个不使用 OpenResty 的 Nginx 集…

GRAPE——RLAIF微调VLA模型:通过偏好对齐提升机器人策略的泛化能力(含24年具身模型汇总)

前言 24年具身前沿模型大汇总 过去的这两年&#xff0c;工作之余&#xff0c;我狂写大模型与具身的文章&#xff0c;加之具身大火&#xff0c;每周都有各种朋友通过CSDN私我及我司「七月在线」寻求帮助/指导(当然&#xff0c;也欢迎各大开发团队与我司合作共同交付&#xff09…

Appium 2.0:移动自动化测试的革新之旅

关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理&#xff0c;构建成功的基石 在自动化测试工作之前&#xff0c;你应该知道的10条建议 在自动化测试中&#xff0c;重要的不是工具 在移动应用开发的领域中&#xff0c;Appium 作为一款强大的自动化测试工具&#xf…

Mysql SQL 超实用的7个日期算术运算实例(10k)

文章目录 前言1. 加上或减去若干天、若干月或若干年基本语法使用场景注意事项运用实例分析说明2. 确定两个日期相差多少天基本语法使用场景注意事项运用实例分析说明3. 确定两个日期之间有多少个工作日基本语法使用场景注意事项运用实例分析说明4. 确定两个日期相隔多少个月或多…

VSCode设置ctrl或alt+mouse(left)跳转

总结&#xff1a; &#xff08;1&#xff09;VSCode初次远程连接服务器时&#xff0c;需要在服务器上下载 python 拓展&#xff0c;然后选择对应的环境 &#xff08;2&#xff09;VSCode设置ctrl或altmouse(left)跳转到定义

VBA 64位API声明语句第005讲

跟我学VBA&#xff0c;我这里专注VBA, 授人以渔。我98年开始&#xff0c;从源码接触VBA已经20余年了&#xff0c;随着年龄的增长&#xff0c;越来越觉得有必要把这项技能传递给需要这项技术的职场人员。希望职场和数据打交道的朋友&#xff0c;都来学习VBA,利用VBA,起码可以提高…

可扩展性设计架构模式——事件驱动架构

事件驱动架构&#xff08;Event-Driven Architecture, EDA&#xff09;是一种可扩展性设计软件架构模式&#xff0c;它通过事件来触发和通信&#xff08;以事件为核心&#xff09;&#xff0c;实现不同系统组件之间的解耦&#xff08;促进应用程序或系统部件之间的松耦合通信&a…

covid-vaccine-availability-using-flask-server

使用烧瓶服务器获得 Covid 疫苗 原文:https://www . geesforgeks . org/co vid-疫苗-可用性-使用-烧瓶-服务器/ 在本文中&#xff0c;我们将使用 Flask Server 构建 Covid 疫苗可用性检查器。 我们都知道&#xff0c;整个世界都在遭受疫情病毒的折磨&#xff0c;唯一能帮助我们…

设计模式从入门到精通之(三)单例模式

单例模式&#xff1a;只留一份独特的存在 在现代软件设计中&#xff0c;有些对象是必须确保"独一无二"的&#xff0c;比如程序中的配置管理器、线程池、数据库连接等。如果允许这些对象被反复创建&#xff0c;不仅会浪费系统资源&#xff0c;还可能导致程序逻辑出错。…

WordPress Crypto 插件 身份认证绕过漏洞复现(CVE-2024-9989)

0x01 产品简介 WordPress Crypto插件是指那些能够为WordPress网站提供加密货币支付、信息显示或交易功能的插件。这些插件通常与WordPress电子商务插件(如WooCommerce)集成,使网站能够接受多种加密货币支付,或展示加密货币实时信息。支持多种加密货币支付,付款直接进入钱…

hashMap追问

HashMap 7/8区别 不同点&#xff1a; &#xff08;1&#xff09;JDK1.7用的是头插法&#xff0c;而JDK1.8及之后使用的都是尾插法&#xff0c;那么他们为什么要这样做呢&#xff1f;因为JDK1.7是用单链表进行的纵向延伸&#xff0c;当采用头插法时会容易出现逆序且环形链表死…

网络安全:路由技术

概述 路由技术到底研究什么内容 研究路由器寻找最佳路径的过程 路由器根据最佳路径转发数据包 知识点&#xff0c;重要OSRF,BGP1.静态路由原理 路由技术分类 静态路由和动态路由技术 静态路由&#xff1a;是第一代路由技术&#xff0c;由网络管理员手工静态写路由/路径告知路…

IIS设置IP+端口号外网无法访问的解决方案

在IIS将站点设置为IP端口访问&#xff0c;假设端口为8080&#xff0c;设好后&#xff0c;服务器上可以访问&#xff0c;外网无法访问。 通常是端口8080没有加入【入站规则】的缘故&#xff0c;将8080端口加入【入站规则】即可&#xff0c;操作如下&#xff1a; 一、ctrlr 输入 …

使用 apply 方法将其他列的值传入 DataFrame 或 Series 的函数,来进行更灵活的计算或操作

可以使用 apply 方法将其他列的值传入 DataFrame 或 Series 的函数&#xff0c;来进行更灵活的计算或操作。apply 方法允许你逐行或逐列地对 DataFrame 或 Series 的元素进行操作&#xff0c;而且你可以将其他列的值作为参数传递给函数。 示例&#xff1a;使用 apply 结合其他…

计算机毕业设计Django+Tensorflow音乐推荐系统 音乐可视化 卷积神经网络CNN LSTM音乐情感分析 机器学习 深度学习 Flask

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

高速网络数据包处理中的内核旁路技术

该PPT详细介绍了Linux网络栈中数据包的传输路径、内核旁路技术的必要性以及具体的内核旁路技术&#xff0c;包括用户空间数据包处理和用户空间网络栈。主要内容概述&#xff1a; 数据包在Linux网络栈中的旅程&#xff1a;描述了数据包从发送到接收的完整路径&#xff0c;包括各…