MySQL 排序的那些事儿

书接上回

上次发了几张图,给了几个MySQL Explain的场景,链接在这儿:你是不是MySQL老司机?来看看这些explain结果你能解释吗?MySQL 夺命6连问

我们依次来分析下这6个问题。

在分析之前,我们先来了解一下MySQL中的排序。
MySQL 排序主要有以下几种方式:

  1. 文件排序(Filesort)
  2. 索引排序(Index Order)

文件排序(Filesort)

文件排序还是比较有歧义的。字面意思就是使用文件排序,但是实际又不是只使用文件,根据具体情况而定,也就是文件排序不一定涉及磁盘文件的读写。

在使用文件排序算法时,MySQL会先尝试是不是可以在排序缓冲区(Sort Buffer)中排序,如果内存放不下要排序的数据集,MySQL才会选择使用磁盘临时文件。

这里有两个关键点需要注意:

  1. 先尝试排序缓冲区(Sort Buffer)排序,缓冲区大小不够才使用文件
  2. 使用文件是使用临时文件

我们只是MySQL有一个配置是Sort_buffer_size,用来配置一个连接的排序缓冲区,MySQL在排序时使用这个缓冲区。

file

另外一点就是临时文件,我们要知道临时文件不一定涉及文件读写,因为临时文件可能是在内存中也可能是在硬盘上。这个需要你根据实际情况来决定使用硬盘还是内存。如果使用基于内存的临时文件系统,那么在Linux临时文件系统中,向临时文件写数据会先写入内存,如果内存空间不足那么才会将内存中的数据交换到磁盘
看看kernel.org对临时文件系统的解释:

file

如果你使用硬盘的文件系统,比如:xfs,ext4等速度虽然不如tmpfs,但是更稳定。

怎么查询MySQL 临时文件配置

show variables like 'tmpdir'

COPY

file

我们看到值是/tmp,然后在使用df -h /tmp来查看是什么文件系统:

file

总结思考

以上两点让我们可以做一些优化:

  1. 如果涉及排序,可以把sort_buffer_size设置大点
  2. 如果使用Tmpfs就把MySQL物理内存配置的大点
  3. 如果使用xfs/ext4就用高速SSD硬盘

文件排序流程

当然,以下是结构化的过程描述:

  1. MySQL根据Where条件匹配行

  2. 然后在Sort Buffer中存一下排序所需要的列值(排序键值,行指针,以及查询所需的列)

  3. Sort Buffer满的时候使用快速排序算法进行排序,然后将排序好的数据写入临时文件中,同时还得记录一下这个文件,一般是记录文件描述符,就是一个int值(在Linux系统中)

  4. 对上面的步骤循环,直到所有扫描完所有Where条件匹配到的行

  5. 到这儿的时候,MySQL可能已经得到了非常多的临时文件(MySQL中交Chunk)

  6. 然后使用归并排序并和到一个结果文件

  7. 然后读取这个文件返回结果集

那么在使用Filesort进行排序是,MySQL使用快速排序对Sort buffer中的数据进行排序,然后使用归并排序对临时文件进行排序。
快排:

file

归并排:

file

索引排序(Index Order)

索引排序就比较简单了,就是如果查询可以使用索引,那么MySQL就使用扫描索引进行排序。如果是正序Explain的Extra列会显示空,如果是倒叙那么Explain就显示backword index scan

索引的组织结构就是B+树,天然有序。

Backward index scan是MySQL 8.0提供的优化特性。

几个例子

我们有一张trade_user表,表结构数据行数如下:

  1. 表结构

    file

  2. 数据行

file

使用文件排序

我们现在来使用name字段进行排序,

explain select * from trade_user order by name asc limit 10;

COPY

Type列为ALL,Extra列为Using filesort
这表示对trade_order表进行全表扫描,排序使用文件排序算法。
explain结果如下:

file

使用索引排序

现在我们修改一下表结构,对name字段增加索引:

alter table trade_user add index idx_name (name);
show indexes from trade_user;

COPY

我们可以看到idx_name索引是visible的,这是MySQL 8.0的新特性,索引是否对优化器可见。

file

我们来执行刚才的SQL:

explain select * from trade_user order by name asc limit 10;

COPY

这次我们执行会看到: Type列为Index, Extra列为NULL

file

这个就是使用了索引进行排序。

现在我们修改一下SQL,把asc修改为desc

explain select * from trade_user order by name desc limit 10;

COPY

我们看到输出和刚才的差别是:Extra列显示Backward index scan,这就是使用了MySQL 8.0的反向索引扫描

file

文件排序和索引排序的差别

文件排序

我们先把idx_name设置为不可见来分析下执行过程:

alter table trade_user alter index idx_name invisible;-- 这里我们添加一个analyze
explain analyze select * from trade_user order by name desc limit 10;

COPY

输出如下:

file

我们可以在输出中看到:

Table scan on trade_user  (cost=52799 rows=521335) (actual time=0.0305..236 rows=524991 loops=1)

COPY

这个SQL需要进行全表扫描,开销很大,数据行越多,开销越大。

索引排序

我们先把idx_name设置为可见来分析下执行过程:

alter table trade_user alter index idx_name visible;-- 这里我们添加一个analyze
explain analyze select * from trade_user order by name desc limit 10;

COPY

输出如下:

file

我们可以在输出中看到:

Index scan on trade_user using idx_name (reverse)  (cost=0.0128 rows=10) (actual time=1.76..1.79 rows=10 loops=1)

COPY

索引排序的开销就很小。

analyze怎么看

倒序看,我们看下我们刚才的两个输出怎么看:

-- 文件排序
3 -> Limit: 10 row(s)  (cost=52799 rows=10) (actual time=281..281 rows=10 loops=1)
2    -> Sort row IDs: trade_user.`name` DESC, limit input to 10 row(s) per chunk  (cost=52799 rows=521335) (actual time=281..281 rows=10 loops=1)
1        -> Table scan on trade_user  (cost=52799 rows=521335) (actual time=0.0382..221 rows=524991 loops=1)-- 索引排序1 -> Limit: 10 row(s)  (cost=0.0128 rows=10) (actual time=1.76..1.79 rows=10 loops=1)
2    -> Index scan on trade_user using idx_name (reverse)  (cost=0.0128 rows=10) (actual time=1.76..1

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

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

相关文章

P6维护:P6 数据库迁移Step by Step

前言 根据大家的近期给的提议,这里简单介绍如何迁移P6数据库,场景选取为从将P6从ORACLE迁移到SQLServer。 Oracle Primavera P6 PPM 以及 EPPM 均有其自带的migrate工具完成数据库迁移,整个操作也较为傻瓜式,只要有基本的数据库…

Etcd Raft 协议(进阶篇)

前言 在正式开始介绍 Raft 协议之间,我们有必要简单介绍一下其相关概念。在分布式系统中,一致性是比较常见的概念,所谓一致性指的是集群中的多个节点在状态上达成一致。在程序和操作系统不会崩溃、硬件不会损坏、服务器不会掉电、网络绝对可靠…

分页多线程处理大批量数据

1.业务场景 因为需要从一个返利明细表中获取大量的数据,生成返利报告,耗时相对较久,作为后台任务执行。但是后台任务如果不用多线程处理,也会要很长时间才能处理完。 另外考虑到数据量大,不能一次查询所有数据在内存…

C# WPF编程-事件

C# WPF编程-路由事件 路由事件概要路由事件的三种方式 WPF事件WPF最重要的5类事件:生命周期事件 鼠标事件键盘事件多点触控输入原始触控 路由事件概要 路由事件是具有更强传播能力的事件,它们可在元素树中向上冒泡和向下隧道传播,并沿着传播…

Pink老师Echarts教学笔记

可视化面板介绍 ​ 应对现在数据可视化的趋势,越来越多企业需要在很多场景(营销数据,生产数据,用户数据)下使用,可视化图表来展示体现数据,让数据更加直观,数据特点更加突出。 01-使用技术 完成该项目需…

AIGC——ComfyUI使用SDXL双模型的工作流(附件SDXL模型下载)

SDXL算法概述 SDXL(Stable Diffusion XL)是Stable Diffusion公司发布的一款图像生成大模型。在以往的模型基础上,SDXL进行了极大的升级,其base模型参数数量达到了35亿,refiner模型参数数量达到了66亿。SDXL与之前的版…

STM32---DHT11温湿度传感器与BH1750FVI光照传感器(HAL库、含源码)

写在前面:本节我们学习使用两个常见的传感器模块,分别为DHT11温湿度传感器以及BH1750FVI光照传感器,这两种传感器在对于环境监测中具有十分重要的作用,因为其使用简单方便,所以经常被用于STM32的项目之中。今天将使用分享给大家&a…

NO9 蓝桥杯单片机实践之串口通信的使用

1 回顾 串口通信的代码编写结构还是与中断一样,不同的是: 初始中断函数条件涉及到串口通信相关的寄存器和定时器1相关的寄存器(定时器1用于产生波特率),但初始条件中的中断寄存器只考虑串口通信而不考虑定时器1。 vo…

基于华为ensp的企业网络规划(新版)

基于华为ensp的企业网络规划(新版) 第一章 项目概述1.1 项目总体描述1.2 项目总体功能要求 第二章 可行性分析2.1 经济效益分析2.2 项目分析2.3 技术可行性分析2.4 项目风险分析 第三章 需求分析3.1 总体需求3.2 具体需求3.3 非功能需求 第四章 总体设计…

Day44:WEB攻防-PHP应用SQL盲注布尔回显延时判断报错处理增删改查方式

目录 PHP-MYSQL-SQL操作-增删改查 PHP-MYSQL-注入函数-布尔&报错&延迟 基于布尔的SQL盲注-逻辑判断(需要有回显,没回显搞不了)跟union需要的条件差不多 基于时间的SQL盲注-延时判断(不需要任何回显) 基于报错的SQL盲注-报错回显(需要报错回显,没报错回…

保研复习概率论1

1.什么是随机试验(random trial)? 如果一个试验满足试验可以在相同的条件下重复进行、试验所有可能结果明确可知(或者是可知这个范围)、每一次试验前会出现哪个结果事先并不确定,那么试验称为随机试验。 …

FileZilla 链接服务器提示 20 秒连接超时

FileZilla 有个默认设置是如果 20 秒没有数据的话会自动中断链接。 Command: Pass: **************** Error: Connection timed out after 20 seconds of inactivity Error: Could not connect to server修改配置 这个配置是可以修改的,修改的步骤为: …