mysql 排序底层原理解析

前言

本章详细讲下排序,排序在我们业务开发非常常见,有对时间进行排序,又对城市进行排序的。不合适的排序,将对系统是灾难性的,这个不是危言耸听。可能有些人会想,对于排序mysql 是怎么实现的,它的底层原理是怎么样的,如果我加上分页,排序是不是就会快一些。关于这些问题,本章详细讲解。

有人经常问我,mysql 优化的规则,总是不假思索的说ESR,E 是 equal ,S是sort 。可见排序有多么重要,为了讲解方便,我先画个思维导图。

上图标的1,2 是mysql 配置文件可以配置的。可以通过 show variables like 'max_length_for_sort_data'; 可以具体的配置。从图上我们可以看到mysql 排序分为全字段排序,和 rowid 。这是两大类,里面又分为内存排序,文件排序,我将从这2大类4小类讲解。

全字段排序

由上图可以看出 Extra = Using filesort 就表示了排序,但此时还不能判断是文件排序还是内存排序

可以根据下面介绍的方法,来确定一个排序语句是否使用了临时文件

/* 打开optimizer_trace,只对本线程有效 */
SET optimizer_trace='enabled=on'; 
​
/* @a保存Innodb_rows_read的初始值 */
select VARIABLE_VALUE into @a from  performance_schema.session_status where variable_name = 'Innodb_rows_read';
​
/* 执行语句 */
select city, name,age from t where city='杭州' order by name limit 1000; 
​
/* 查看 OPTIMIZER_TRACE 输出 */
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`\G
​
/* @b保存Innodb_rows_read的当前值 */
select VARIABLE_VALUE into @b from performance_schema.session_status where variable_name = 'Innodb_rows_read';
​
/* 计算Innodb_rows_read差值 */
select @b-@a;
​
### 

Number_of_tmp_files>0 就表示文件排序,没有就表示是内存排序。sort_buffer_size 越小,那么 Number_of_tmp_files 就会越大,文件排序用的是归并排序,也就是把数据分给多个文件,每个文件排序后,最终合并一个文件。

上面sort_mode 可以看到,这是一个全字段排序,什么是全字段排序,就拿上面这个sql 语句来说,city ,name,age 都在文件里,对name 进行排序

这个排序的内部是这么实现的:

  1. 初始化 sort_buffer,确定放入 name、city、age 这三个字段;

  2. 从索引 city 找到第一个满足 city='杭州’ 条件的主键 id

  3. 到主键 id 索引取出整行,取 name、city、age 三个字段的值,存入 sort_buffer 中;

  4. 从索引 city 取下一个满足 city='杭州’ 的主键 id;

  5. 重复步骤 3、4 直到 city 的值不满足查询条件为止

  6. 对 sort_buffer 中的数据按照字段 name 做快速排序;

  7. 按照排序结果取前 1000 行返回给客户端。

由此我们发现,排序会对表的所有的记录进行排序,然后在取出1000条

rowid

如果 排序数据的长度超过了 max_length_for_sort_data 就是 rowid排序。排序数据的长度就是指拿上面这个例子说 name、city、age 这三个字段大于 max_length_for_sort_data 就是rowid 排序。为什么会这样的呢,mysql 会尽量用内存排序,字段越长,占用空间越大,未了提高排序效率,就会用rowid 排序。

rowid排序的步骤是这样的:

  1. 初始化 sort_buffer,确定放入两个字段,即 name 和 id;

  2. 从索引 city 找到第一个满足 city='杭州’条件的主键 id

  3. 到主键 id 索引取出整行,取 name、id 这两个字段,存入 sort_buffer 中;

  4. 从索引 city 取下一个记录的主键 id;

  5. 重复步骤 3、4 直到不满足 city='杭州’条件为止,

  6. 对 sort_buffer 中的数据按照字段 name 进行排序;

  7. 遍历排序结果,取前 1000 行,并按照 id 的值回到原表中取出 city、name 和 age 三个字段返回给客户端。

我们可以看到 rowid 会多访问一次表,在mysql 看来,排序的复杂度高于回表的复杂度,这也是一种取舍。

综上可以看出不管是内存排序还是文件排序,都是很繁琐的,那么有没有对于这个问题有没有优化点了,在前面我们已经讲过了,索引一定是有序的,如果我们对city,name 建一个联合索引,就不用mysql 重新排序,因为索引本身就是有序的。

就是如下所示:

alter table t add index city_user(city, name);

但是上面虽然不用mysql 用文件排序,但是还是要回表的,那还有没有进一步的优化呢,我们可以考虑用覆盖索引

如下所示:

alter table t add index city_user_age(city, name, age);

这样就不用回表了,用explain 来看 Extra using index

大家要综合考虑吧,索引越多,索引越大,会影响插入的速度的。

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

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

相关文章

Android 地图SDK 绘制点 删除 指定

问题 Android 地图SDK 删除指定绘制点 详细问题 笔者进行Android 项目开发&#xff0c;对于已标记的绘制点&#xff0c;提供撤回按钮&#xff0c;即删除绘制点&#xff0c;如何实现。 解决方案 新增绘制点 private List<Marker> markerList new ArrayList<>…

Oracle数据库:使用 bash脚本 + 定时任务 自动备份数据

Oracle数据库&#xff1a;使用 bash脚本 定时任务 自动备份数据 1、前言2、为什么需要自动化备份&#xff1f;3、编写备份脚本4、备份脚本授权5、添加定时任务6、重启 crond / 检查 crond 服务状态7、备份文件检查 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

解决:InheritableThreadLocal与线程池共用的问题

回顾一下上篇文章&#xff1a;InheritableThreadLocal和ThreadLocal的区别和使用场景 上篇文章介绍道&#xff0c;InheritableThreadLocal 是 ThreadLocal 的一个子类&#xff0c;它不但继承了ThreadLocal的所有特性&#xff0c;父线程中的 InheritableThreadLocal 变量的值可以…

AI赋能写作:AI大模型高效写作一本通

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

Java学习笔记(15)

JDK7前时间相关类 Date时间类 Simpledateformat Format 格式化 Parse 解析 默认格式 指定格式 EE&#xff1a;表示周几 Parse&#xff1a;把字符串时间转成date对象 注意&#xff1a;创建对象的格式要和字符串的格式一样 Calendar日历类 不能创建对象 Getinstance 获取当…

深度学习pytorch——索引与切片

indexing import torch a torch.rand(4,3,28,28) # 表示4张28*28的rgb图 print(a[0].shape) # a[0]获得第一张图片 print(a[0,0].shape) # a[0,0]获得第一张图片的r图 print(a[0,0,2,4]) # 获得第一张图片第一个通道的一个像素点&#xf…

【C#】【SAP2000】读取SAP2000中所有Frame对象在指定工况的温度荷载值到Grasshopper中

if (build true) {// 连接到正在运行的 SAP2000// 使用 COM 接口获取 SAP2000 的 API 对象cOAPI mySapObject (cOAPI)System.Runtime.InteropServices.Marshal.GetActiveObject("CSI.SAP2000.API.SapObject");// 获取 SAP2000 模型对象cSapModel mySapModel mySap…

4262. 空调(acwing)

文章目录 4262. 空调题目描述贪心差分难点解析差分数组的更新计算最小命令数量更新差分数组反向差分计算计算最小指令数量 4262. 空调 题目描述 Farmer John 的 N头奶牛对他们牛棚的室温非常挑剔。 有些奶牛喜欢温度低一些&#xff0c;而有些奶牛则喜欢温度高一些。 Farmer…

MySQL数据库操作学习(1)

文章目录 一_初识MySQL数据库1、数据库2、数据库分类1.关系型数据库2.非关系型数据库&#xff08;备用&#xff09; 3、数据库概念1.数据&#xff08;data&#xff09;2.数据库&#xff08;database&#xff09;3.数据管理系统&#xff08;DBMS&#xff09; 二、MySQL库操作了解…

315曝光黑灰产业链:主板机

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 315晚会曝光主板机黑灰产业链&#xff0c;主板机是什么呢?可能很多人还不知道。在这里松松给大家普及一下&#xff0c;也欢迎大家关注卢松松哟! 主板机是什么呢? 通过报废手机的主板&#xff0c;拆出来后组装成主…

【XR806开发板试用】xr806 RTC实验

一、例程编译、烧录确认 首先按照全志在线文档平台的点灯教程确保能正常编译、烧录和点灯&#xff1a;https://xr806.docs.aw-ol.com/… 确保例程没问题后&#xff0c;我们再改造例程&#xff0c;实现我们想要的功能 二、代码编写 我们将hello工程复制一份改文件夹名为rtc_demo…

专升本 C语言笔记-06 常用的3种输入输出函数

1.scanf() 与 printf() 的使用 scanf() 格式化输入数据 格式:scanf("格式控制字符串",参数地址列表) scanf("%d,%d,%d",&a,&b,&c); printf("a %d\n",a); printf("b %d\n",b); printf("c %d\n",c); 注意 注…

【数据结构】堆

目录 一、树的介绍以及堆 1.树 2.二叉树以及堆 二、堆的实现 1.heap.h 2.heap.c 1)堆的初始化和销毁 2&#xff09; 堆的插入 3&#xff09;堆的删除 4&#xff09;取堆顶数据 5&#xff09;堆的数据个数 6&#xff09;堆的判空 3.test.c 一、树的介绍以及堆 …

跨境电商选品实战——Ownips公开数据信息安全采集+Python爬虫轻松搞定Lazada电商选品

文章目录 一、引言二、Lazada电商平台选品实战2.1、分析Lazada电商平台的商品列表接口2.2、定位商品列表计算逻辑2.3、封装高质量住宅IP2.4、运行爬虫 三、数据处理及选品分析四、Ownips——企业级全球静态住宅IP&#xff0c;高效采集公开数据 一、引言 互联网与外贸的结合&am…

Maya自定义工具架

有时候我们需要自己定义工具架上的内容&#xff0c;比如将一个工具放到工具架上&#xff0c;或者删除一个工具 添加一个工具 例如我们想在多边形建模栏位上添加一个分离按钮&#xff0c;默认 1 先切换到想要添加的工具架栏位 2 打开菜单&#xff0c;找到我们想添加的工具 …

前端实现websocket通信讲解(vue2框架)

websocket&#xff1a; WebSocket是HTML5下一种新的协议&#xff08;websocket协议本质上是一个基于tcp的协议&#xff09;它实现了浏览器与服务器全双工通信&#xff0c;能更好的节省服务器资源和带宽并达到实时通讯的目的Websocket是一个持久化的协议 websocket提供的api&a…

70城市房价同比继续下降

据北京商报的最新报道&#xff0c;昨&#xff08;3月15日&#xff09;天国家统计局发布《2月70个大中城市商品住宅销售价格》显示&#xff0c;2024年2月&#xff0c;在70个大中城市中&#xff0c;各线城市商品住宅销售价格同比继续下降。 一线城市二手住宅销售价格同比下降6.3…

拿捏指针(二)

个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 目录 前言 数组与指针 数组名的理解 指针数组与数组指针 指针数组 数组指针 数组传参 一维数组传参的本质 二维数组传参的本质 二维数组…

Github Gitlab SSH 密钥配置

1. 操作流程 生成密钥&#xff08;非对称加密&#xff09; ssh-keygen -t rsa -C "your_emailexample.com"注意&#xff0c;这里的 -C 表示注释&#xff0c;没有什么用&#xff0c;主要是标记密钥避免自己遗忘。 查看密钥&#xff08;公钥&#xff09; //进入所属…

Go 日期时间包装器:15条更便捷的时间处理

在Go编程中&#xff0c;处理日期和时间是一项常见任务&#xff0c;涉及到精确性和灵活性。尽管Go的标准库提供了时间包&#xff08;time&#xff09;用于处理时间相关操作&#xff0c;但在某些情况下&#xff0c;我们需要额外的实用函数来简化这些任务。本文将介绍一系列实用函…