mysql order by 排序原理

sql语句按照指定的字段进行排序是查询数据时是一个很常见的操作。当涉及到大量数据时,对于 ORDER BY 操作,可以考虑为相应的列添加索引,如果不使用索引,mysql会使用filesort来进行排序。

filesort

filesort虽然有file,但是不一定是文件排序,要分情况。下面来看下排序的具体逻辑。

filesort会将查询行数据放入sort_buffer中,然后按排序字段进行排序。sort_buffer的大小有变量sort_buffer_size来控制,默认大小256kb。

mysql> SELECT @@sort_buffer_size;
+--------------------+
| @@sort_buffer_size |
+--------------------+
|             262144 |

如果要排序的数据内容小于sort_buffer_size,排序在内存中即可完成;否则filesort会使用临时文件进行排序。数据越多生成的临时文件越多,每份文件单独排序后再归并合并成一个有序的结果。

临时文件存放再 tmpdir 变量指定的目录下,排序完成后会自动删除。

mysql> select @@tmpdir;
+----------+
| @@tmpdir |
+----------+
| /tmp     |

如果使用了filesort,在explain的Extra会显示:Using filesort。是否使用了临时文件还需要根据具体的执行过程来判断。下面通过information_schema.OPTIMIZER_TRACE表来查看是否使用临时文件。

1、准备一个t_user表,首先开启optimizer_trace

mysql> SET optimizer_trace='enabled=on';

2、然后执行查看explain这里再Extra会有Using filesort。

mysql> explain select * from t_user order by username;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 2700 |   100.00 | Using filesort |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.00 sec)

3、执行查询

select * from t_user order by username;

注意这里是执行查询,不是explain,否则下面一步看不到信息

4、查看OPTIMIZER_TRACE

SELECT * FROM information_schema.OPTIMIZER_TRACE;

OPTIMIZER_TRACE一共有4列:

QUERY:表示当前查询语句

TRACE: 包含查询优化器的trace信息,json格式

MISSING_BYTES_BEYOND_MAXMEM:丢失字节数。

在trace内容中有“filesort_summary”部分是关于filesort处理信息,如上面查询对应的filesort_summary

mysql8:

"filesort_summary": {"memory_available": 262144,"key_size": 481,"row_size": 6591,"max_rows_per_buffer": 39,"num_rows_estimate": 2700,"num_rows_found": 2800,"num_initial_chunks_spilled_to_disk": 8,"peak_memory_used": 264192,"sort_algorithm": "std::sort","sort_mode": "<fixed_sort_key, packed_additional_fields>"
}

mysql5.7:

"filesort_summary": {"rows": 2800,"examined_rows": 2800,"number_of_tmp_files": 6,"sort_buffer_size": 261784,"sort_mode": "<sort_key, rowid>"
}

这里看到5.7和8差别还是有点大,但是几个主要的字段还是差不多的。这里以5.7的trace信息来看。

sort_buffer_size是sort_buffer的大小。

rows:数据行数

number_of_tmp_files:临时文件数,如果该值为0,则表示未使用临时文件,sort_buffer够用。

sort_mode:排序方式。这个指定了参与排序的数据内容不同。

sort_key, rowid:sort_buffer中加载的数据只有排序字段(sort_key)和rowid,rowid用来排序后再回表查询获取行数据。

sort_key, additional_fields:sort_buffer中加载数据包含所有的要查询的字段。

sort_key, packed_additional_fields:和上面的additional_fields差不多,只是有些可变长度会进行压缩。

那么sort_mode这两种类型一种有所有查询字段,一种只有排序字段,查询优化器是根据什么选择的呢。这里有一个参数max_length_for_sort_data,如果查询的数据行记录超过该值,则会采用sort_key, rowid模式,否则会采用sort_key, additional_fields模式。不过这个值在MySQL 8.0.20被标为过时了,建议通过调整sort_buffer_size大小来控制join_buffer大小,尽量避免使用磁盘临时文件。这两种排序模式比较:additional_fields模式不需要回表,如果查询的列比较多,可能会导致sort_buffer所能容纳的行数据变少;rowid模式每行数据很小,sort_buffer可以加载更多的行,但是最后返回数据要回表。不同数据量场景,要合理设置sort_buffer_size和max_length_for_sort_data搭配。

这里看到排序的过程,一行行拿出来进行比较,数据量大还会使用到临时文件,还是比较耗时的。那么有没有更快的方法呢?那就是使用索引。

使用索引

为什么使用索引会快?因为构建后的索引就是天然有序的,不需要再经过一行行逐一对sort_key进行比较。跳过额外的filesort。

排序使用索引的情况一般在Extra中只有Using index。使用索引一般场景:

1、查询条件中有排序索引

2、索引覆盖,查询的列都在对应的索引中

3、多列索引排序,满足最左匹配

4、排序方向一致

这只是一般的规则,下面结合几个具体的例子来看看。

t_user表上有复合索引 (username,gender,department) 还有索引(phone)

例1:

SELECT uid,phone FROM t_user ORDER BY phone;

查询列都在索引上(uid是主键),Using index

例2:

SELECT * FROM t_user ORDER BY phone;

索引不包含查询访问的所有列,则仅当索引访问比其他访问方法更高效时才使用该索引.这里查询优化器选择了Using filesort。 不太理解?

例3:

SELECT uid,phone FROM t_user WHERE uid<20 ORDER BY phone;

虽然查询内容是索引覆盖,但是where条件不在索引上(不是同一个索引),Using filesort。

这个应该可以理解一个索引筛选出来的数据内容对另一个索引是无序的。

例4:

SELECT username,gender FROM t_user  ORDER BY username,gender;
SELECT username,gender FROM t_user WHERE username='a' ORDER BY gender;

查询内容索引覆盖,where满足索引最左匹配部分,Using index。

例5:

SELECT username,gender FROM t_user WHERE username LIKE 'a%'  ORDER BY username desc,gender ;

多列排序,第一列排序username满足使用索引条件,gender和username排序方向相反,无法使用索引,会进行依次filesort。

例6:

SELECT username,gender FROM t_user WHERE username LIKE 'a%'  ORDER BY username,department ;

username排序使用filesort,department排序不满足最左匹配,中间复合索引断开(缺少gender)使用filesort。

这里只看了几个常见例子,可能有些场景比这复杂的多。想一想能使用到索引排序一个最基本的条件:当前要查询的数据范围(where筛选后)在排序列(对应的索引)是有序的。然后才考虑覆盖索引等其它需要满足的条件。

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

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

相关文章

拦截器配置,FeignClient根据业务规则实现微服务动态路由

文章目录 业务场景拦截器用法Open Feign介绍 业务场景 我们服务使用Spring Cloud微服务架构&#xff0c;使用Spring Cloud Gateway 作为网关&#xff0c;使用 Spring Cloud OpenFeign 作为服务间通信方式我们现在做的信控平台&#xff0c;主要功能之一就是对路口信号机进行管控…

数据结构中的时间复杂度和空间复杂度基础

目录 数据结构 数据结构中的基本名词 数据 数据对象 数据元素 数据项 数据类型 数据对象、数据元素和数据项之间的关系 数据结构及分类 逻辑结构 物理结构 算法 算法的特点 算法设计上的要求 算法效率的衡量 时间复杂度 大O渐进表示法 最坏情况和平均情况 常…

关于现有预报气象大模型的能力上限思考

从2022年开始&#xff0c;以华为pangu weather为代表的气象大模型及fuxi、fengwu等相继涌现&#xff0c;公开发表的文章里也展示了模型与ec预报性能的对比&#xff0c;并且这些大模型也公开了相应的代码或模型&#xff0c;便于人人都可测试使用&#xff08;如何在本地部署大模型…

R语言学习case10:ggplot基础画图Parallel Coordinate Plot 平行坐标图

step1: 导入ggplot2库文件 library(ggplot2)step2&#xff1a;带入自带的iris数据集 iris <- datasets::irisstep3&#xff1a;查看数据信息 dim(iris)维度为 [150,5] head(iris)查看数据前6行的信息 step4&#xff1a;利用ggplot工具包绘图 plot5 <- ggparcoord(…

Pandas数据预处理之数据标准化-提升机器学习模型性能的关键步骤【第64篇—python:数据预处理】

文章目录 Pandas数据预处理之数据标准化&#xff1a;提升机器学习模型性能的关键步骤1. 数据标准化的重要性2. 使用Pandas进行数据标准化2.1 导入必要的库2.2 读取数据2.3 数据标准化 3. 代码解析4. 进一步优化4.1 最小-最大缩放4.2 自定义标准化方法 5. 处理缺失值和异常值5.1…

HGAME 2024 WEEK 1 :web ezHTTP

题目&#xff1a; 看到这个就知道是文件头伪造 第一想法就是Referer伪造 所以伪造 Referer: vidar.club 然后构造伪造的Referer 然后提示通过那些东西访问页面&#xff0c;User-Agent: 是构造你浏览器访问信息的&#xff0c;所以复制右边那一串替代就好了 然后要求我们从本地…

STM32Cubmax stm32f103zet6 SPI通讯

一、基本概念 SPI 是英语 Serial Peripheral interface 的缩写&#xff0c;顾名思义就是串行外围设备接口。是 Motorola 首先在其 MC68HCXX 系列处理器上定义的。 SPI 接口主要应用在 EEPROM&#xff0c; FLASH&#xff0c;实时时 钟&#xff0c; AD 转换器&#xff0c;还有数…

Vue3入门到实战笔记04--生命周期和自定义hook

13. 生命周期 概念&#xff1a;Vue组件实例在创建时要经历一系列的初始化步骤&#xff0c;在此过程中Vue会在合适的时机&#xff0c;调用特定的函数&#xff0c;从而让开发者有机会在特定阶段运行自己的代码&#xff0c;这些特定的函数统称为&#xff1a;生命周期钩子 规律&am…

Linux在云计算领域的重要作用

在云计算领域&#xff0c;Linux扮演着至关重要的角色。以下是Linux在云计算领域中的重要作用&#xff1a; 稳定性和安全性&#xff1a;Linux操作系统具有稳定性和安全性&#xff0c;可以有效地保护用户的数据安全。它具有各种安全功能&#xff0c;可以防止未经授权的访问&…

【Linux系统化学习】文件描述符fd

目录 基础IO预备知识 C语言文件接口 "w"的方式打开&#xff0c;fputs写入 以"a"的方式打开&#xff0c;fputs写入 使用位图传参 系统调用操作文件 open的使用 第一种形式 第二种形式 write() 文件描述符 文件描述符和进程的关系 默认的三个IO流…

C语言:函数递归

创作不易&#xff0c;给个三连吧&#xff01;&#xff01; 一、什么是递归 递归式一种解决问题的方法&#xff0c;在C语言中&#xff0c;递归就是自己调用自己。 递归的思想&#xff1a; 把⼀个⼤型复杂问题层层转化为⼀个与原问题相似&#xff0c;但规模较小的⼦问题来求解…

考研数据结构笔记(2)

线性表 线性表的定义线性表的基本操作lnitList(&L)DestroyList(&L)Listlnsert(&L,i,e)ListDelete(&L,i,&e)LocateElem(L,e)GetElem(L,i)Length(L)PrintList(L)Empty(L)Tips:引用值 小结 根据数据结构的三要素–逻辑结构、数据的运算、存储结构&#xff0c;…

嵌入式学习Day14 C语言 --- 位运算

位运算 注意&#xff1a;符号位也遵循这个规则 一、按位与(&) 运算规则&#xff1a;一假则假 int a 0x33;a & 0x55;0011 00110101 0101 &----------0001 0001 //0x11 二、按位或(|) 运算规则&#xff1a;一真则真 int a 0x33;a |0x55;0011 00110101 0101 |…

Asp .Net Core 集成 NLog

简介 NLog是一个基于.NET平台编写的日志记录类库&#xff0c;它可以在应用程序中添加跟踪调试代码&#xff0c;以便在开发、测试和生产环境中对程序进行监控和故障排除。NLog具有简单、灵活和易于配置的特点&#xff0c;支持在任何一种.NET语言中输出带有上下文的调试诊断信息…

Python 数据分析库之polars使用详解

概要 数据分析是现代应用程序和业务决策的关键组成部分。Python 作为一门强大的编程语言,拥有丰富的数据处理库和工具,其中之一就是 Polars。Polars 是一个现代化的数据操作和分析库,它提供了高性能的数据操作功能,支持链式方法调用,并且兼容 Pandas 和 Arrow 格式。本文…

嵌入式Linux学习DAY19

函数接口 fgetc(a):从流中读取一个字符----调用一次读取向后读取一次&#xff08;因为被操作数为流&#xff09; 流被读完后会产生错误----用来作为读取结束的条件 fgetc/fputc与getchar/putchar的区别-------没有区别 fputs(a,b):将a打印到b内&#xff0c;若b为stdout&…

微信小程序合集更更更之实现仿网易云播放动效

实现效果 写在最后&#x1f352; 源码&#xff0c;关注&#x1f365;苏苏的bug&#xff0c;&#x1f361;苏苏的github&#xff0c;&#x1f36a;苏苏的码云~

鸿蒙开发-UI-组件导航-Tabs

鸿蒙开发-UI-组件 鸿蒙开发-UI-组件2 鸿蒙开发-UI-组件3 鸿蒙开发-UI-气泡/菜单 鸿蒙开发-UI-页面路由 鸿蒙开发-UI-组件导航-Navigation 文章目录 一、基本概念 二、导航 1.底部导航 2.顶部导航 3.侧边导航 4.导航栏限制滑动 三、导航栏 1.固定导航栏 2.滚动导航栏 3…

写后台接口,前后台数据对接(vue+springboot)

一、怎么写接口&#xff1f;&#xff1f;&#xff1f; 1.Entity&#xff08;定义一堆属性之类的&#xff09; altins>getter和setter方法 2.Controller 3.Service&#xff08;查询出数据&#xff09; 调用了一个方法 4.Mapper 5.回到service&#xff08;返回数据&#x…

2024年微信公众号链接爬取

通过输入&#xff08;或文件导入&#xff09;公众号名称&#xff0c;即可爬取该公众号所有历史文章。 通过公众号官方网站调用API&#xff0c;打开开发者工具后发现有 打开后发现有搜索结果的fakeid&#xff0c;这是每个公众号的标识。 点击某公众号后出现 这是具体公众号文章…