当前位置: 首页 > news >正文

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列是属于已经使用了索引的情况。那为啥还会慢呢?

Pasted image 20231114181147.png

因为即使是使用了索引,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 属性在使用时分别有两次调用&#xff1a…...

vue3中祖孙组件之间的通信provide和inject

一、在vue3中新增的祖孙之间通信的方式 provide和inject是Vue中的两个相关功能&#xff0c;它们一起提供了一种祖孙组件之间共享数据的方式。父组件可以使用provide来提供数据&#xff0c;而子孙组件可以使用inject来接收这些数据。 二、使用 父组件中部分代码 <script&g…...

月影下的时光机:Python中的日期、时间、农历、节气和时区探秘

前言 在现代软件开发中&#xff0c;对日期、时间和时区的准确处理至关重要。无论是全球化应用的开发&#xff0c;还是与时序数据相关的任务&#xff0c;都需要强大而灵活的工具。Python作为一门流行的编程语言&#xff0c;提供了丰富的标准库和第三方库&#xff0c;使得处理日…...

【Bazel】Bazel 学习笔记

本文简单记录下 Bazel 使用过程中的一些知识点。 目录 文章目录 目录Bazel 目录结构BUILD 构建规则常用构建规则 Bazel 命令bazel buildbazel query Mac 安装 Bazel Bazel 是谷歌推出的一个开源的构建工具&#xff0c;工作原理与 make、maven 或 gradle 等其他构建工具类似。但…...

2023年“华为杯”第二十届中国研究生数学建模成绩数据分析(末尾有吃席群)

目录 0引言1、数据大盘1.1 官方数据1.2 分赛题统计数据1.2.1 A-F 获奖数1.2.2 A-F 获奖率 2、分学校统计获奖情况&#xff08;数模之星没有统计&#xff09;3、 数模之星4、吃席群5、写在最后的话 0引言 2023年华为杯成绩于2023年9月22-26日顺利举行&#xff0c;来自国际和全国…...

Linux文件和文件夹命令详解

1.Linux文件类型详解 常见的Linux文件类型&#xff1a; 普通文件&#xff08;Regular File&#xff09;&#xff1a;&#xff08;例如文本文件、二进制文件、图片、视频和压缩文件等&#xff1b;&#xff09; 普通文件是最常见的文件类型&#xff0c;存储了实际的数据&#xf…...

MIKE水动力笔记20_由dfs2网格文件提取dfs1断面序列文件

本文目录 前言Step 1 MIKE Zero工具箱Step 2 提取dfs1 前言 在MIKE中&#xff0c;dfs2是一个一个小格格的网格面的时间序列文件&#xff0c;dfs1是一条由多个点组成的线的时间序列文件。 如下两图&#xff1a; 本博文内容主要讲如何从dfs2网格文件中提取dfs1断面序列文件。 …...

微服务nacos实战入门

注册中心 在微服务架构中&#xff0c;注册中心是最核心的基础服务之一 主要涉及到三大角色&#xff1a; 服务提供者 ---生产者 服务消费者 服务发现与注册 它们之间的关系大致如下&#xff1a; 1.各个微服务在启动时&#xff0c;将自己的网络地址等信息注册到注册中心&#x…...

PyCharm 远程连接服务器并使用服务器的 Jupyter 环境

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…...

HBase中的数据表是如何用CHAT进行分区的?

问CHA&#xff1a;HBase中的数据表是如何进行分区的&#xff1f; CHAT回复&#xff1a; 在HBase中&#xff0c;数据表是水平分区的。每一个分区被称为一个region。当一个region达到给定的大小限制时&#xff0c;它会被分裂成两个新的region。 因此&#xff0c;随着数据量的增…...

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…...

分布式应用服务拆分

需求落地分布式应用服务 将需求转化为分布式应用服务的过程可以按照以下步骤进行&#xff1a; 理解需求&#xff1a;首先&#xff0c;你需要仔细阅读和理解业务需求。与相关的利益相关者&#xff08;如业务分析师、产品经理等&#xff09;进行沟通&#xff0c;确保你对需求的理…...

matplotlib 绘制双纵坐标轴图像

效果图&#xff1a; 代码&#xff1a; 由于使用了两组y axis&#xff0c;如果直接使用ax.legend绘制图例&#xff0c;会得到两个图例。而下面的代码将两个图例合并显示。 import matplotlib.pyplot as plt import numpy as npdata np.random.randint(low0,high5,size(3,4)) …...

74基于matlab的PSO-ELM的多输入,单输出结果预测,输出训练集和测试机预测结果及误差。

基于matlab的PSO-ELM的多输入&#xff0c;单输出结果预测&#xff0c;输出训练集和测试机预测结果及误差&#xff0c;适应度值。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 74matlabPSO-ELM多输入单输出 (xiaohongshu.com)...

shell之head命令

head命令 head命令是UNIX和Linux环境中常用的命令&#xff0c;用于在标准输出上显示文件的开头内容。 具体来说&#xff0c;head命令默认会显示给定文件开头的10行内容。如果指定了多个文件名&#xff0c;head命令会逐个显示每个文件的开头内容&#xff0c;并在每个文件显示的…...

网络安全之了解安全托管服务(MSS)

数字化已深入千行百业。数字化将给各行各业带来巨大的变化&#xff0c;现实世界和虚拟世界也将联系得更加紧密。随着云计算、大数据等新技术结合企业级业务的落地&#xff0c;数字时代的安全面临着前所未有的新挑战。近年来&#xff0c;网络安全问题日益严重&#xff0c;在企业…...

linux进程间通信之共享内存(mmap,shm_open)

共享内存&#xff0c;顾名思义就是允许两个不相关的进程访问同一个逻辑内存&#xff0c;共享内存是两个正在运行的进 程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中&#xff0c…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...