【mysql学习篇】Order by与Group by优化以及排序算法详解
一、Order by与Group by优化
Case1:

分析: 利用最左前缀法则:中间字段不能断,因此查询用到了name索引,从key_len=74也能看出,age索引列用在排序过程中,因为Extra字段里没有using filesort
注意: order by age 虽然用到了索引,但是不会在key_len列体现
Case 2:

分析: 从explain的执行结果来看:key_len=74,查询使用了name索引,由于用了position进行排序,跳过了age,出现了Using filesort。
注意: 这里跳过了age,这里position是无序的,所以不会走索引
Case 3:

分析: 查找只用到索引name,age和position用于排序,无Using filesort。
Case 4:

分析: 和Case 3中explain的执行结果一样,但是出现了Using filesort,因为索引的创建顺序为name,age,position,但是排序的时候age和position颠倒位置了。
重点注意: 这边颠倒age和position,mysql不会像前面提到的where后面一样优化最左前缀
Case 5:

分析: 与Case 4对比,在Extra中并未出现Using filesort,因为age为 常量,在排序中被优化,所以索引未颠倒,不会出现Using filesort。
Case 6:

分析: 虽然排序的字段列与索引顺序一样,且order by默认升序,这里position desc变成了降序,导致与索引的排序方式不同,从而产生Using filesort。Mysql8以上版本有降序索引可以支持该种查询方式。
Case 7:

分析: 对于排序来说,多个相等条件也是范围查询
Case 8:

可以用覆盖索引优化

二、Using filesort 文件排序原理详解
filesort文件排序方式
在使用explain分析查询的时候,利用有序索引获取有序数据显示Using index。如果MySQL在排序的时候没有使用到索引那么就会输出using filesort,即使用文件排序。
文件排序是通过相应的排序算法,将取得的数据在内存中进行排序:
- MySQL需要将数据在内存中进行排序,所使用的内存区域也就是我们通过sort_buffer_size系统变量所设置的sort buffer(排序区)。
- 这个sort buffer是每个Thread独享的,所以说可能在同一时刻在MySQL中可能存在多个sort buffer内存区域。
1. 双路排序(又叫回表排序模式)
- 首先根据相应的条件取出相应的
排序字段和可以直接定位行数据的行 ID - 然后在 sort buffer (内存排序)中进行排序,排序完后需要再次取回其它需要的字段;
- 用trace工具可以看到sort_mode信息里显示< sort_key, rowid >
第一遍扫描出需要排序的字段,然后进行排序后,根据排序结果,第二遍再扫描一下需要select的列数据。这样会引起大量的随机IO,效率不高,但是节约内存。排序使用quick sort,但是如果内存不够则会按照 block 进行排序,将排序结果写入磁盘文件,然后再将结果合并。
2. 单路排序
- 一次性取出满足条件行的
所有字段,然后在sort buffer内存中进行排序; - 用trace工具可以看到sort_mode信息里显示< sort_key, additional_fields >或者< sort_key, packed_additional_fields >
- 不需要回表获取其他字段效率高,但将所有字段取出,在sort buffer中排序,占用内存
如何选择文件排序方式
MySQL 通过比较系统变量 max_length_for_sort_data(默认1024字节) 的大小和需要查询的字段总大小来判断使用哪种排序模式。
- 如果 字段的总长度小于max_length_for_sort_data ,那么使用 单路排序模式
- 如果 字段的总长度大于max_length_for_sort_data ,那么使用 双路排序模式
示例验证下各种排序方式:

查看下这条sql对应trace结果如下(只展示排序部分):
mysql> set session optimizer_trace="enabled=on",end_markers_in_json=on; --开启trace
mysql> select * from employees where name = 'zhuge' order by position;
mysql> select * from information_schema.OPTIMIZER_TRACE;trace排序部分结果:
"join_execution": { --Sql执行阶段"select#": 1,"steps": [{"filesort_information": [{"direction": "asc","table": "`employees`","field": "position"}] /* filesort_information */,"filesort_priority_queue_optimization": {"usable": false,"cause": "not applicable (no LIMIT)"} /* filesort_priority_queue_optimization */,"filesort_execution": [] /* filesort_execution */,"filesort_summary": { --文件排序信息"rows": 10000, --预计扫描行数"examined_rows": 10000, --参与排序的行"number_of_tmp_files": 3, --使用临时文件的个数,这个值如果为0代表全部使用的sort_buffer内存排序,否则使用的磁盘文件排序"sort_buffer_size": 262056, --排序缓存的大小,单位Byte"sort_mode": "<sort_key, packed_additional_fields>" --排序方式,这里用的单路排序} /* filesort_summary */}] /* steps */} /* join_execution */mysql> set max_length_for_sort_data = 10; --employees表所有字段长度总和肯定大于10字节
mysql> select * from employees where name = 'zhuge' order by position;
mysql> select * from information_schema.OPTIMIZER_TRACE;trace排序部分结果:
"join_execution": {"select#": 1,"steps": [{"filesort_information": [{"direction": "asc","table": "`employees`","field": "position"}] /* filesort_information */,"filesort_priority_queue_optimization": {"usable": false,"cause": "not applicable (no LIMIT)"} /* filesort_priority_queue_optimization */,"filesort_execution": [] /* filesort_execution */,"filesort_summary": {"rows": 10000,"examined_rows": 10000,"number_of_tmp_files": 2,"sort_buffer_size": 262136, "sort_mode": "<sort_key, rowid>" --排序方式,这里用的双路排序} /* filesort_summary */}] /* steps */} /* join_execution */mysql> set session optimizer_trace="enabled=off"; --关闭trace
我们先看单路排序的详细过程:
- 从索引name找到第一个满足 name = ‘zhuge’ 条件的主键 id
- 根据主键 id 取出整行,取出所有字段的值,存入 sort_buffer 中
- 从索引name找到下一个满足 name = ‘zhuge’ 条件的主键 id
- 重复步骤 2、3 直到不满足 name = ‘zhuge’
- 对 sort_buffer 中的数据按照字段 position 进行排序
- 返回结果给客户端
我们再看下双路排序的详细过程:
- 从索引 name 找到第一个满足 name = ‘zhuge’ 的主键id
- 根据主键 id 取出整行,把排序字段 position 和主键 id 这两个字段放到 sort buffer 中
- 从索引 name 取下一个满足 name = ‘zhuge’ 记录的主键 id
- 重复 3、4 直到不满足 name = ‘zhuge’
- 对 sort_buffer 中的字段 position 和主键 id 按照字段 position 进行排序
- 遍历排序好的 id 和字段 position,按照 id 的值回到原表中取出 所有字段的值返回给客户端
三、总结
-
其实对比两个排序模式,单路排序会把所有需要查询的字段都放到 sort buffer 中,而双路排序只会把主键和需要排序的字段放到 sort buffer 中进行排序,然后再通过主键回到原表查询需要的字段。
-
如果 MySQL 排序内存 sort_buffer 配置的比较小并且没有条件继续增加了,可以适当把 max_length_for_sort_data 配置小点,让优化器选择使用双路排序算法,可以在sort_buffer 中一次排序更多的行,只是需要再根据主键回到原表取数据。
-
如果 MySQL 排序内存有条件可以配置比较大,可以适当增大 max_length_for_sort_data 的值,让优化器优先选择全字段排序(单路排序),把需要的字段放到 sort_buffer 中,这样排序后就会直接从内存里返回查询结果了。
-
所以,MySQL通过 max_length_for_sort_data 这个参数来控制排序,在不同场景使用不同的排序模式,从而提升排序效率。
注意: 如果全部使用sort_buffer内存排序一般情况下效率会高于磁盘文件排序,但不能因为这个就随便增大sort_buffer(默认1M),mysql很多参数设置都是做过优化的,不要轻易调整。
相关文章:
【mysql学习篇】Order by与Group by优化以及排序算法详解
一、Order by与Group by优化 Case1: 分析: 利用最左前缀法则:中间字段不能断,因此查询用到了name索引,从key_len74也能看出,age索引列用在排序过程中,因为Extra字段里没有using filesort 注意…...
【业务功能篇60】Springboot + Spring Security 权限管理 【终篇】
4.4.7 权限校验扩展 4.4.7.1 PreAuthorize注解中的其他方法 hasAuthority:检查调用者是否具有指定的权限; RequestMapping("/hello")PreAuthorize("hasAuthority(system:user:list)")public String hello(){return "hello Sp…...
文章详情页 - 评论功能的实现
目录 1. 准备工作 1.1 创建评论表 1.2 创建评论实体类 1.3 创建 mapper 层评论接口和对应的 xml 实现 1.4 准备评论的 service 层 1.5 准备评论的 controller 层 2. 总的初始化详情页 2.1 加载评论列表 2.1.1 实现前端代码 2.1.2 实现后端代码 2.2 查询当前登录用户的…...
使用贝叶斯滤波器通过运动模型和嘈杂的墙壁传感器定位机器人研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Day 69-70:矩阵分解
代码: package dl;import java.io.*; import java.util.Random;/** Matrix factorization for recommender systems.*/public class MatrixFactorization {/*** Used to generate random numbers.*/Random rand new Random();/*** Number of users.*/int numUsers…...
数据结构:树的存储结构
学习树之前,我们已经了解了二叉树的顺序存储和链式存储,哪么我们如何来存储普通型的树结构的数据?如下图1: 如图1所示,这是一颗普通的树,我们要如何来存储呢?通常,存储这种树结构的数…...
Vue前端渲染blob二进制对象图片的方法
近期做开发,联调接口。接口返回的是一张图片,是对二进制图片处理并渲染,特此记录一下。 本文章是转载文章,原文章:Vue前端处理blob二进制对象图片的方法 接口response是下图 显然,获取到的是一堆乱码&…...
Java的标记接口(Marker Interface)
Java中的标记接口(Marker Interface)是一个空接口,接口内什么也没有定义。它标识了一种能力,标识继承自该接口的接口、实现了此接口的类具有某种能力。 例如,jdk的com.sun.org.apache.xalan.internal.xsltc.trax.Temp…...
Kafka基础架构与核心概念
Kafka简介 Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。架构特点是分区、多副本、多生产者、多订阅者,性能特点主要是…...
观察者模式与观察者模式实例EventBus
什么是观察者模式 顾名思义,观察者模式就是在多个对象之间,定义一个一对多的依赖,当一个对象状态改变时,所有依赖这个对象的对象都会自动收到通知。 观察者模式也称为发布订阅模式(Publish-Subscribe Design Pattern)࿰…...
科普 | OSI模型
本文简要地介绍 OSI 模型 1’ 2’ 3。 更新:2023 / 7 / 23 科普 | OSI模型 术语节点链路协议网络拓扑 概念作用结构应用层表示层会话层传输层网络层数据链路层物理层 数据如何流动OSI 和TCP/IP 的对应关系和协议参考链接 术语 节点 节点( Node &#…...
redis相关异常之RedisConnectionExceptionRedisCommandTimeoutException
本文只是分析Letture类型的Redis 池化连接出现的连接超时异常、读超时异常问题。 1.RedisConnectionException 默认是10秒。 通过如下可以配置: public class MyLettuceClientConfigurationBuilderCustomizer implements LettuceClientConfigurationBuilderCusto…...
Merge the squares! 2023牛客暑期多校训练营4-H
登录—专业IT笔试面试备考平台_牛客网 题目大意:有n*n个边长为1的小正方形摆放在边长为n的大正方形中,每次可以选择不超过50个正方形,将其合并为一个更大的正方形,求一种可行的操作使所有小正方形都被合并成一个n*n的大正方形 1…...
STM32 串口学习(二)
要用跳线帽将PA9与RXD相连,PA10与TXD相连。 软件设计 void uart_init(u32 baud) {//UART 初始化设置UART1_Handler.InstanceUSART1; //USART1UART1_Handler.Init.BaudRatebound; //波特率UART1_Handler.Init.WordLengthUART_WORDLENGTH_8B; //字长为 8 位数据格式U…...
点大商城V2_2.5.0 全开源版 商家自营+多商户入驻 百度+支付宝+QQ+头条+小程序端+unipp开源前端安装测试教程
安装测试环境:Nginx 1.20PHP7.2MySQL 5.6 修复了无法上传开放平台问题 安装说明: 1、上传后端目录至网站 2、导入提供的数据库文件 3、修改数据库配置文件根目录下config.php,增加数据库用户名和密码 4、网站后台直接访问网址ÿ…...
“深入理解SpringBoot:从入门到精通“
标题:深入理解Spring Boot:从入门到精通 摘要:本文将介绍Spring Boot的基本概念和核心特性,并通过示例代码演示如何使用Spring Boot构建一个简单的Web应用程序。 1. 简介 Spring Boot是一个开源的Java框架,旨在简化基…...
PCB绘制时踩的坑 - SOT-223封装
SOT-223封装并不是同一的,细分的话可以分为两种常用的封装。尤其是tab脚的属性很容易搞错。如果你想着用tab脚连接有属性的铺铜,来提高散热效率,那么你一定要注意你购买的器件tab脚的属性。 第一种如下图,第1脚为GND,第…...
Go语法入门 + 项目实战
👂 Take me Hand Acoustic - Ccile Corbel - 单曲 - 网易云音乐 第3个小项目有问题,不能在Windows下跑,懒得去搜Linux上怎么跑了,已经落下进度了.... 目录 😳前言 🍉Go两小时 🔑小项目实战 …...
QT控件通过qss设置子控件的对齐方式、大小自适应等
一些复杂控件,是有子控件的,每个子控件,都可以通过qss的双冒号选择器来选中,进行独特的样式定义。很多控件都有子控件,太多了,后面单独写一篇文章来介绍各个控件的子控件。这里就随便来几个例子 例如下拉列…...
基于java在线收银系统设计与实现
摘要 科技的力量总是在关键的地方改变着人们的生活,不仅如此,我们的生活也是离不开这样或者那样的科技改变,有的消费者没有时间去商场购物,那么电商和快递的结合让端口到消费者的距离不再遥远;有的房客因地域或者工作的…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
