mysql group by 执行原理及千万级别count 查询优化
大家好,我是蓝胖子,前段时间mysql经常碰到慢查询报警,我们线上的慢sql阈值是1s,出现报警的表数据有 7000多万,经常出现报警的是一个group by的count查询,于是便开始着手优化这块,遂有此篇,记录下自己优化过程中的心得。
优化慢sql前,肯定是要懂sql的查询逻辑,所以我先介绍下group by 语句的执行逻辑。
group by 执行逻辑
环境准备
拿下面这张表举例,这是一张记录文件夹id和用户id关联关系的表。其中dir_id代表文件夹id,uid代表用户id,还有个唯一索引是uniq_dir_id。
create table t_dir_user
(
id bigint unsigned auto_increment
primary key,
dir_id bigint default 0 not null,
uid bigint default 0 not null,
constraint uniq_dir_id
unique (dir_id, uid)
)
表一共有7000多万的数据。下面开始介绍使用group by 语句时sql执行的原理。
没有用到索引的情况
先说下结论,group by后面的列如果不能使用上索引,那么则会产生临时表且很可能产生文件排序的情况。
group by 语句有分 使用到索引和没有使用到索引的情况,先看看没有使用到索引的情况。假如我想查询在一些文件夹范围内,用户关注的文件夹数量。那我可以写出下面这样的sql。
explain select count(1), uid
from t_dir_user
where dir_id in (1803620,4368250,2890924,2033475,3038030)
group by uid;
使用explain分析时,会发现这个查询是使用到索引的,且Extra 那一栏会出现下面的信息。
Using index condition; Using temporary; Using filesort
上述信息代表了查询是使用到了索引来做where条件查询,并且使用到了临时表和文件排序。
注意📢📢 ❗️ 临时表和文件排序这两个操作都是性能不佳的操作,写sql时应尽量避免。
现在来对这种情况做更加具体的分析,在上述例子中,mysql相当于建立了一张临时表,具体是内存的临时表还是磁盘的临时表要看临时表数据量大小,内存放不下会放到磁盘上。
临时表一列存放需要分组的值,上述案例中就是 uid,一列存放统计出来的count值,mysql会一遍扫描uniq_dir_id索引,一边向这个临时表中写入数据或更新count值,当索引扫描完成后,再将填满数据的临时表做下排序然后返回给客户端。注意这个排序的行为,如果需要排序的数据量很大则会产生文件排序,否则则是内存排序。
使用到索引的情况
再来看看group by 后跟的列能使用到索引的情况。
先说下结论,使用到索引的时候,mysql会使用内置的聚合函数来进行操作,而不是创建临时表。并且节省了排序这一步,这种方式会更高效。
还是拿上面t_dir_user 这张表举例,这次我们要查一定文件夹范围内,一个文件夹与多少个用户关联。我们可以这样写sql,
explain select count(1), dir_id
from t_dir_user
where dir_id in (1803620,4368250,2890924,2033475,3038030)
group by dir_id;
此时explain分析后你会发现,虽然使用的是相同的索引,但是Extra这一栏的信息已经变了,Extra信息如下,
Using index condition; Using aggregate; Using index
Using aggregate 这条sql会使用mysql内置的聚合函数进行分组聚合的操作。
我们来具体分析下,因为group by此次是按dir_id文件夹id进行分组的,而dir_id刚好可以用上dir_id和uid建立的联合索引uniq_dir_id,并且索引是有序的,这样mysql在扫描索引的时候,就是一个文件夹id的索引数据扫描完成后,再次去扫描下一个文件夹id的索引数据,扫描的同时会对该文件夹id的count值进行累加。 这样一个文件夹的索引数据扫描完成后刚好就能知道这个文件夹id关联的uid的count值,并将这个值发送给客户端。
所以,整个过程其实是一边扫描索引对特定文件夹id的count值进行累加,一边将累加后的结果返回给客户端的过程。
注意📢📢,mysql返回给客户端的结果并不是全部查询出来后才返回给客户端,而是可以边查边返回的。
整个过程是没有用上临时表的。这样的查询会更加高效。
使用索引的情况下如何优化千万级count group by查询
在了解完group by语句的执行逻辑后,我对线上的sql进行了分析,发现线上的sql的group by列是属于已经使用了索引的情况。那为啥还会慢呢?

因为即使是使用了索引,group by的过程还是会有扫描索引和进行累加的过程,由于扫描的数据量太大了,最终导致了sql整体耗时还是很慢,超过了1s的阈值。
既然如此,那就换一种优化思路,这也是对大数据量的聚合统计的一种常用手段。 业务大部分时候都是读多写少的,可以建立一张新表专门用于记录对应的文件夹管理的用户数,每次关联关系发生变化时,同时再更新下这张统计表的数量即可。而业务在查询数量时,则直接查统计表中的数据。 这种优化非常适合大数据量的统计。
除此以外,甚至还可以使用elasticsearch 这类型数据库存数据,在这个案例里,相当于就把t_dir_user整张表的数据同步到elasticsearch中,并且做mysql到elasticsearch集群数据的实时同步机制,这样以后在查询对应文件夹的关联人数时,可以直接在elasticsearch进行查询。elasticsearch会对每个字段建立倒排索引。由于倒排索引中会存储该索引的记录条数,在这个案例中就是dir_id对应的记录条数,所以在用elasticsearch进行dir_id的分组count查询时是相当快的。
我们线上已经有elasticsearch同步部分mysql表的机制了,基于此,我选择了方案2,直接在之前同步表中新增了t_dir_user这张表,并且修改了业务查询文件夹下关联人数的逻辑,改由直接查询elasticsearch。
其实,你可以发现由于elasticsearch的倒排索引内直接记录了数量信息,这个和由mysql建立新的统计表记录数量,原理其实是一致的,就是将高频的读count查询改由低频的更新操作。
相关文章:
mysql group by 执行原理及千万级别count 查询优化
大家好,我是蓝胖子,前段时间mysql经常碰到慢查询报警,我们线上的慢sql阈值是1s,出现报警的表数据有 7000多万,经常出现报警的是一个group by的count查询,于是便开始着手优化这块,遂有此篇,记录下…...
Linux的几个常用基本指令
目录 1. ls 指令2.pwd命令3.cd 指令4. touch指令5.mkdir指令6.rmdir指令 && rm 指令7.man指令8.cp指令9.mv指令10.cat指令 1. ls 指令 语法: ls [选项][目录或文件] 功能:对于目录,该命令列出该目录下的所有子目录与文件。对于文件&…...
mac中安装Homebrew
1、Homebrew是什么? 软件安装管理工具 2、先检查电脑中是否已经安装了Homebrew 打开终端输入:brew 提示命令没有找到,说明电脑没有安装Homebrew 如果提示上述图片说明Homebrew已经安装成功 3、安装Homebrew 进入https://brew.sh/ 复制的命…...
Vue23的计算属性(computed)
Vue2&3的计算属性(computed) Vue2的计算属性 原理:data中的属性通过计算得到新的属性,称为计算属性(computed)。computed 具有 getter 和 setter 属性 getter 属性在使用时分别有两次调用:…...
vue3中祖孙组件之间的通信provide和inject
一、在vue3中新增的祖孙之间通信的方式 provide和inject是Vue中的两个相关功能,它们一起提供了一种祖孙组件之间共享数据的方式。父组件可以使用provide来提供数据,而子孙组件可以使用inject来接收这些数据。 二、使用 父组件中部分代码 <script&g…...
月影下的时光机:Python中的日期、时间、农历、节气和时区探秘
前言 在现代软件开发中,对日期、时间和时区的准确处理至关重要。无论是全球化应用的开发,还是与时序数据相关的任务,都需要强大而灵活的工具。Python作为一门流行的编程语言,提供了丰富的标准库和第三方库,使得处理日…...
【Bazel】Bazel 学习笔记
本文简单记录下 Bazel 使用过程中的一些知识点。 目录 文章目录 目录Bazel 目录结构BUILD 构建规则常用构建规则 Bazel 命令bazel buildbazel query Mac 安装 Bazel Bazel 是谷歌推出的一个开源的构建工具,工作原理与 make、maven 或 gradle 等其他构建工具类似。但…...
2023年“华为杯”第二十届中国研究生数学建模成绩数据分析(末尾有吃席群)
目录 0引言1、数据大盘1.1 官方数据1.2 分赛题统计数据1.2.1 A-F 获奖数1.2.2 A-F 获奖率 2、分学校统计获奖情况(数模之星没有统计)3、 数模之星4、吃席群5、写在最后的话 0引言 2023年华为杯成绩于2023年9月22-26日顺利举行,来自国际和全国…...
Linux文件和文件夹命令详解
1.Linux文件类型详解 常见的Linux文件类型: 普通文件(Regular File):(例如文本文件、二进制文件、图片、视频和压缩文件等;) 普通文件是最常见的文件类型,存储了实际的数据…...
MIKE水动力笔记20_由dfs2网格文件提取dfs1断面序列文件
本文目录 前言Step 1 MIKE Zero工具箱Step 2 提取dfs1 前言 在MIKE中,dfs2是一个一个小格格的网格面的时间序列文件,dfs1是一条由多个点组成的线的时间序列文件。 如下两图: 本博文内容主要讲如何从dfs2网格文件中提取dfs1断面序列文件。 …...
微服务nacos实战入门
注册中心 在微服务架构中,注册中心是最核心的基础服务之一 主要涉及到三大角色: 服务提供者 ---生产者 服务消费者 服务发现与注册 它们之间的关系大致如下: 1.各个微服务在启动时,将自己的网络地址等信息注册到注册中心&#x…...
PyCharm 远程连接服务器并使用服务器的 Jupyter 环境
❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…...
HBase中的数据表是如何用CHAT进行分区的?
问CHA:HBase中的数据表是如何进行分区的? CHAT回复: 在HBase中,数据表是水平分区的。每一个分区被称为一个region。当一个region达到给定的大小限制时,它会被分裂成两个新的region。 因此,随着数据量的增…...
rabbitMQ的direct模式的生产者与消费者使用案例
消费者C1的RoutingKey 规则按照info warn 两种RoutingKey匹配 绑定队列console package com.esint.rabbitmq.work03;import com.esint.rabbitmq.RabbitMQUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback;/*** 消费者01的消息接受*/ p…...
分布式应用服务拆分
需求落地分布式应用服务 将需求转化为分布式应用服务的过程可以按照以下步骤进行: 理解需求:首先,你需要仔细阅读和理解业务需求。与相关的利益相关者(如业务分析师、产品经理等)进行沟通,确保你对需求的理…...
matplotlib 绘制双纵坐标轴图像
效果图: 代码: 由于使用了两组y axis,如果直接使用ax.legend绘制图例,会得到两个图例。而下面的代码将两个图例合并显示。 import matplotlib.pyplot as plt import numpy as npdata np.random.randint(low0,high5,size(3,4)) …...
74基于matlab的PSO-ELM的多输入,单输出结果预测,输出训练集和测试机预测结果及误差。
基于matlab的PSO-ELM的多输入,单输出结果预测,输出训练集和测试机预测结果及误差,适应度值。数据可更换自己的,程序已调通,可直接运行。 74matlabPSO-ELM多输入单输出 (xiaohongshu.com)...
shell之head命令
head命令 head命令是UNIX和Linux环境中常用的命令,用于在标准输出上显示文件的开头内容。 具体来说,head命令默认会显示给定文件开头的10行内容。如果指定了多个文件名,head命令会逐个显示每个文件的开头内容,并在每个文件显示的…...
网络安全之了解安全托管服务(MSS)
数字化已深入千行百业。数字化将给各行各业带来巨大的变化,现实世界和虚拟世界也将联系得更加紧密。随着云计算、大数据等新技术结合企业级业务的落地,数字时代的安全面临着前所未有的新挑战。近年来,网络安全问题日益严重,在企业…...
linux进程间通信之共享内存(mmap,shm_open)
共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进 程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中,…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
