MySQL排序的艺术:你真的懂 Order By吗?

Mysql实现对某一字段排序并将排名写入另一字段 最近业务上碰到这样一个需求,需要对表按照某一个字段进行排序,并且将得到的排名写入对应的排名字段。这个需求于我而言确实没有遇到过,好在试着摸索一番得以解决,故写博客记录一下。希望这篇博客对大家有所帮助!!! 阅读详情

前言

业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。

换句话说,业务中使用 SELECT 语句的时候除了不可避免的搭配 WHERE 以外,还会配合 ORDER BY 进行使用。

今天来好好聊聊 MySQL 的 ORDER BY 排序。


排序算法

说到排序算法,有插入排序、选择排序、归并排序、堆排序、快速排序、计数排序、桶排序、基数排序、冒泡排序、希尔排序、梳排序 ...

关于各种排序算法的排序流程和具体实现,不是本篇博客的重点,不作详细说明。

这里直接贴各类排序算法的时空复杂度:

通常我们实现的这些排序算法,都是在”纯内存“环境中进行。

MySQL 作为数据库难道是在先将所有要排序的数据加载到内存,再应用排序算法吗?


MySQL 的排序方案

在分析 MySQL 的不同的排序方案之前,先来了解 sort buffer 概念。

MySQL 会为每个线程分配固定大小的 sort buffer 用作排序。

sort buffer 是具有逻辑概念的内存区域,大小由 sort_buffer_size 参数控制,默认为 256 kb。

由于 sort buffer 大小固定,而 data(待排序的数据量)并不固定,所以根据 sort buffer 与 data(待排序数据量)的大小差值,可分为内部排序和外部排序:

  • data <= sort buffer:即 sort buffer 够用,这时候 MySQL 只需要在内存中进行排序即可。内部排序使用的是快速排序
  • data > sort buffer:这时候 sort buffer 不够用,MySQL 需要借助外部“容器”(通常是文件)进行排序。通常会将待排序数据分成多个“小文件”,对各个“小文件”进行排序,再汇总成一个有序的“大文件”。外部排序使用的是归并排序

如何验证当前执行的排序语句使用的是内部排序还是外部排序?

可以通过 EXPLAIN 命令来查看,如果在分析结果中的 Extra 字段里包含 Using filesort 字眼,说明执行了外部排序操作。

全字段排序

「全字段排序是指,只要与最终结果集有关的字段都会被放进 sort buffer,而不管该字段本身是否参与排序。」

以下面的 SQL 为例子:

SELECT nick_name, age, phone 
FROM t_user 
WHERE city = "深圳" 
ORDER BY nick_name;

假设 city 字段上有索引,全字段排序的过程:

  1. 从 city 索引树上找到第一条值为深圳的数据,取得 id 之后回表(回到主键索引)取得 nick_name、age、phone 三个字段放入 sort buffer
  2. 从 city 索引树取下一条值为深圳的数据,重复 1 过程,直到下一条数据不满足值为深圳条件
  3. 到这一步,所有 city = 深圳 的数据都在 sort buffer 了。对 nick_name 执行快速排序
  4. 将排序结果返回

可以看到当查询条件本身有索引可用的话,全字段排序的排序过程都在 sort buffer(内存)进行,回表次数为符合条件的数据个数。

当然,如果我们建立的是 city、nick_name、age、phone 的联合索引,还可以实现“索引覆盖”,即在一棵索引树上取得全部所需数据,减少回表(随机读)次数。

不过针对每个查询或排序语句建立联合索引,会导致索引过多,大大降低写入更新数据的速度,以及大大提升数据所需要的存储空间。

生产商对索引的建立修改需要格外谨慎。

rowId 排序

rowId 就是 MySQL 对每行数据的唯一标识符。

当数据表有主键时,rowId 就是表主键;当数据表没有主键或者主键被删除时,MySQL 会自动生成一个长度为 6 字节的 rowId 为作为 rowId。

「rowId 排序是指只将与排序相关的字段和 rowId 放入 sort buffer,其余结果集需要用到的数据在排序完成后,通过 rowId 回表取得。」

全字段排序的流程看着已经十分合理,为什么还需要有个 rowId 排序?

这是我们只需要输出三个字段的情况,假如我们有上百个字段需要返回呢?sort buffer 默认只有 256 kb。能够装下多少行的原始数据行?

所以当待排序的数据行很大的时候,使用全字段排序必然会导致“外部排序”。而且是使用很多临时文件的“外部排序”,效率很低下。

相比全字段排序,rowId 排序的好处是在 sort buffer 大小固定的情况下,sort buffer 能够容纳更多的数据行,能够避免使用或者少使用“外部排序文件”。

缺点是最终返回结果集的时候,需要再次进行回表。

还是之前那个例子:

SELECT nick_name, age, phone 
FROM t_user 
WHERE city = "深圳" 
ORDER BY nick_name;

rowId 排序全过程:

  1. 从 city 索引树上找到第一条值为深圳的数据,取得 id 之后回表(回到主键索引)取得 nick_name 这个与排序相关的字段和主键 id 一起放入 sort buffer
  2. 从 city 索引树取下一条值为深圳的数据,重复 1 过程,直到下一条数据不满足值为深圳条件
  3. 这时候,所有 city = 深圳 的数据都在 sort buffer 了(sort buffer 里面的数据包含两个字段: id 和 nick_name)。对 nick_name 执行快速排序
  4. 利用排序好的数据,使用主键 id 再次回表取其他字段,将结果返回

注意:该步骤 4 中不会等所有排序好的 id 回表完再返回,而是每个 id 回表一次,取得该行数据之后立即返回,所以不会消耗额外的内存。

优先队列排序

无论是使用全字段排序还是 rowId 排序,都不可避免了对所有符合 WHRER 条件的数据进行了排序。

有读者可能会认为,那不是应该的吗?

设想一下,如果我们还搭配着 LIMIT 使用呢?

例如我们在排序语句后添加 LIMIT 3 ,哪怕查出来的数据有 10W 行,我们也只需要前 3 行有序。

为了得到前 3 行数据,而不得不将 10W 行数据载入内存,大大降低了 sort buffer 的利用率。

这时候你可能想到利用“最小堆”、“最大堆”来进行排序。

没错,这正是 MySQL 针对带有 LIMIT 的 ORDER BY 语句的优化:使用优先队列进行排序。

以下面的 SQL 为例子:

SELECT nick_name, age, phone 
FROM t_user 
WHERE city = "深圳" 
ORDER BY nick_name LIMIT 3;

优先队列进行排序的流程:

  1. 在所有待排序的数据,取数量为 LIMIT (本例中为 3)的数据,构建一个堆
  2. 不断地取下一行数据,更新堆节点
  3. 当所有行的扫描完,得到最终的排序结果

如何选择?

现在我们知道有全字段排序和 rowId 排序,那么 MySQL 是如何在这两种排序方案中做选择呢?

由于 rowId 排序相对于全字段排序,不可避免的多了一次回表操作,回表操作意味着随机读,而随机 IO 是数据库中最昂贵的操作。

所以 MySQL 会在尽可能的情况下选择全字段排序。

那么什么情况下 MySQL 会选择 rowId 排序呢,是否有具体的值可以量度?

答案是有的,通过参数 max_length_for_sort_data 可以控制用于排序的行数据最大长度,默认值为 1024 字节。

当单行数据长度超过该值,MySQL 就会觉得如果还用全字段排序,会导致 sort buffer 容纳下的行数太少,从而转为使用 rowId 排序。


临时表排序

通常对于一个执行较慢的排序语句,在使用 EXPLAIN 进行执行过程分析的时候除了能看到 Using filesort 以外,还能看到 Using temporary,代表在排序过程中使用到了临时表。

内存临时表排序

MySQL 优先使用内存临时表。当 MySQL 使用内存临时表时,临时表存储引擎为 memory 。

如果当前 MySQL 使用的是内存临时表的话,将会直接使用 rowId 排序,因为这时候所谓的“回表”只是在内存表中读数据,操作不涉及硬盘的随机 IO 读。

使用 rowId 可以在 sort buffer 容纳给多的行,避免或减少外部排序文件的使用。

磁盘临时表排序

如果系统中很多需要使用临时表的排序语句执行,而又不加以限制,全都使用临时表的话,内存很快就会被打满。

所以 MySQL 提供了 tmp_table_size 参数限制了内存临时表的大小,默认值是 16M。

如果临时表大小超过了tmp_table_size,那么内存临时表就会转成磁盘临时表。

当使用磁盘临时表的时候,表储存引擎将不再是 memory,而是由 internal_tmp_disk_storage_engine 参数控制,默认为 InnoDB 。

这时候 MySQL 会根据单行大小是否超过 max_length_for_sort_data 决定采用全字段排序还是 rowId 排序。


总结

总结一下,MySQL 总是使用 「“最快”」 的排序方案:

  • 当排序数据量不超过 sort buffer 容量时,MySQL 将会在内存使用快速排序算法进行排序(内部排序);当排序数据量超过 sort buffer 容量时,MySQL 将会借助临时磁盘文件使用归并排序算法进行排序(外部排序)
  • 在进行真正排序时,MySQL 会根据数据判断单行长度是否超过 max_length_for_sort_data而决定使用 rowId 排序还是全字段排序,优先选择全字段排序,以减少回表次数
  • 当需要借助临时表的时候,MySQL 会优先使用内存临时表(此时表引擎为 memory 引擎),回内存临时表取数据并不涉及随机读,也不涉及扫描行,效率较高。所以在配合内存临时表的时候,会使用 rowId 排序方式;当内存临时表大小超过 tmp_table_size 限制时,则需要将内存临时表转换为磁盘临时表,这时候由于回表意味着随机读,所以会搭配全字段排序方式

原文链接:
https://mp.weixin.qq.com/s/hFkN8XpGA6mZfQtszZMu3w

 

MySql面试总结(一) Change Buffer 是 MySQL InnoDB 存储引擎中的一种特殊缓存机制,它主要用于缓存对非唯一二级索引页的写操作(插入、更新、删除),而不是立即将这些修改操作应用到磁盘上的索引页。只有在查询需要访问这些被修改的索引页时,或者在后台线程进行定期合并操作时,才会将 Change Buffer 中的修改合并到磁盘上的索引页中。特性InnoDBMyISAMMemoryArchive事务支持是否否否锁机制行级锁表级锁表级锁行级锁外键支持是否否否全文索引。 阅读详情

相关推荐

MySQL排序及性能优化

索引排序(Index Sort):当MySQL可以使用索引完成排序时,会使用索引排序。索引排序的过程是在索引的基础上完成排序,避免了文件排序的磁盘I/O开销。使用覆盖索引:如果查询只需要返回索引列的数据,并且索引列包含了ORDER BY子句中的列,那么可以使用覆盖索引(covering index)。为了提高MySQL的排序性能,可以选择适当的索引,增大排序缓冲区,使用覆盖索引等优化策略。如果查询只需要返回索引列的数据,可以使用覆盖索引来避免对数据行的访问,进一步提高排序性能。参数来调整排序缓冲区的大小。

QvisCs的博客 579

sort函数怎么用mysql_实例详解sort()函数的原理和使用方法

本文主要为大家分享一篇实例详解sort()函数的原理和使用方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧,希望能帮助到大家。sort()方法就是对数组按照一定的条件进行排序。在不带参数的情况下sort()方法默认会将数组元素当作string类型来升序排序,根据它们的unicode码从小到大依次排列.如果想按照自己的条件进行排序,需要传一个比较函数。如下:var arr = [...

weixin_30767863的博客 2976

STM32CubeMX——循迹传感器TCRT5000的使用

前言 人生如逆旅,我亦是行人。 ————苏轼《临江仙·送钱穆父》 一、介绍 TCRT5000描述:(带有晶体管输出的反射光学传感器) TCRT5000是一种反射式光学传感器,它包括一个红外发射器和一个3.5mm引线封装的光电晶体管,可阻挡可见光。还具有1mA 典型被测输出电流,2.5mm峰值工作距离,可应用传感与仪表,工业等行业。 TCRT5000具有紧凑的结构,其中发射光源和探测器布置在同一方向,通过使用来自物体的反射红外光束来感知物体的存在。工作波长为950毫米,探测器由光电晶体管组成

W_Oilpicture的博客 1万+

mysql一对多 排序后取第一条_MySQL 排序的艺术

前言业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。换句话说,业务中使用 SELECT 语句的时候除了不可避免的搭配 WHERE 以外,还会配合 ORDER BY 进行使用。今天来好好聊聊 MySQL 的 ORDER BY 排序。排序算法说到排序算法,有插入排序、选择排序、归并排序、堆排序、快速排序、计数排序、桶排序、基数排序、冒泡排序、希尔排序、梳排序 ...

weixin_29529047的博客 2911

告别Failed to start错误!保姆级教程:用Ubuntu20.04安装盘搞定GRUB与系统服务修复

本文提供Ubuntu20.04系统启动失败的专业修复指南,详细讲解如何利用安装盘解决GRUB与系统服务问题,避免重装系统导致的数据丢失。涵盖分区挂载、chroot环境操作、服务诊断与修复等实用技巧,帮助用户高效恢复系统正常运行。

weixin_32578161的博客 331

手把手教你用CODESYS将旧笔记本改造成软PLC(含证书配置避坑指南)

本文提供了一份详尽的指南,教你如何利用CODESYS平台将闲置旧笔记本改造为一台功能完整的软PLC。内容涵盖从硬件评估、系统实时性优化、软件安装与驱动配置,到关键的证书授权管理避坑指南,旨在帮助自动化工程师和爱好者低成本搭建稳定可靠的学习与开发平台。

weixin_29190573的博客 279

mysql排序sort_MySQL 排序的艺术:你真的懂 Order By 吗?

前言业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。换句话说,业务中使用SELECT语句的时候除了不可避免的搭配WHERE以外,还会配合ORDER BY进行使用。今天来好好聊聊 MySQL 的ORDER BY排序。排序算法说到排序算法,有插入排序、选择排序、归并排序、堆排序、快速排序、计数排序、桶排序、基数排序、冒泡排序、希尔排序、梳排序 ...关于...

weixin_39757739的博客 1650

7系列ZYNQ硬件调试:Vitis无法识别ARM DAP的排查与解决

本文针对7系列ZYNQ开发中Vitis无法识别ARM DAP的典型硬件调试问题,提供了系统性的排查与解决方案。文章深入剖析了问题本质,指出ARM DAP无法访问的核心原因在于PS部分的电源、时钟或复位等硬件基础条件未满足,并重点强调了PS参考时钟(如33.333MHz晶振)的完整性是关键排查点。通过从电源完整性、时钟与复位信号到JTAG连接与焊接的逐步硬件排查,并结合软件配置交叉验证,为开发者提供了清晰的故障定位思路与实战指南。

weixin_29280657的博客 626

MySQL 排序的艺术:你真的懂 Order By 吗?

前言 业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。 换句话说,业务中使用SELECT语句的时候除了不可避免的搭配WHERE以外,还会配合ORDER BY进行使用。 今天来好好聊聊 MySQL 的ORDER BY排序。 排序算法 说到排序算法,有插入排序、选择排序、归并排序、堆排序、快速排序、计数排序、桶排序、基数排序、冒泡排序、希尔排序、梳排序 ... 关于各种排序算法的排序流程和具体实现,不是本篇博客的重点,不作详细说明。 这里直...

m0_70565884的博客 305

SQL注入-靶场通关 Less 1-21

打开Burp工具--打开内嵌浏览器--进入靶场第六关--打开拦截--输入?id=1',如果是正确的,说明不存在注入点,如果错误,说明存在注入点,这里是错误的,需要加上注释--+,在回车看结果是正确的,说明找到了注入点。工具,打开内嵌浏览器,打开拦截,输入http://127.0.0.1/sqli-labs-master/Less-9,然后发送到。id=1'--+,后面都注释了,单引号不闭合,报错说明是数字型SQL注入。设置休眠时间为10s,如果执行SQL语句就会加载,说明正确,存在注入点。

weixin_72104324的博客 1392

NVIDIA平台Xavier/TX2板摄像头驱动开发与TP2850方案开发

本文介绍了在NVIDIA平台上开发Xavier/TX2板摄像头驱动的过程,并结合TP2850方案实现了多路模拟相机输入。我们提供了初始化摄像头和连接TP2850方案的示例代码,并介绍了相关的步骤和注意事项。需要注意的是,以上示例代码仅提供了基本的摄像头初始化和与TP2850通信的框架,你需要根据具体的需求进行进一步开发和配置。你可能需要参考摄像头和TP2850的数据手册以及相关的开发文档,以了解更多详细的配置和操作。此外,你还需要一个支持TP2850方案的硬件设备,并将其连接到Xavier/TX2板上。

PixelLancer的博客 592

mysql order by 算法_MySQL 排序的艺术:你真的懂 Order By 吗?

❝作者:宫水三叶。现微软工程师(Java 后端方向),退役 OIer。更多和 MySQL 面试 & 算法相关内容可点击「这里」关注~更好的阅读体验,请点击查看原文转载需关注公众号联系开白名单 ~❞前言业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。换句话说,业务中使用SELECT语句的时候除了不可避免的搭配WHERE以外,还会配合ORDER ...

weixin_29827071的博客 279

Hermes Agent 安装部署完全指南

Hermes Agent安装部署指南提供了两种安装方式:一键脚本安装和手动分步安装。该AI助手支持多平台运行(Linux/macOS/WSL2),核心功能仅需Git作为前置依赖,其他依赖如Python、Node.js等均由安装脚本自动处理。文档详细介绍了系统要求、依赖管理、配置目录结构、环境变量设置以及10个手动安装步骤,并提供了功能模块化选项,用户可根据需求选择安装语音交互、浏览器自动化等扩展功能。安装完成后可通过hermes doctor命令验证环境,并通过交互式向导完成初始化配置。

简简单单Onlinezuozuo 2622

java order by_MySQL 排序的艺术:你真的懂 Order By 吗?

❝作者:宫水三叶。现微软工程师(Java 后端方向),退役 OIer。更多和 MySQL 面试 & 算法相关内容可点击「这里」关注~❞前言业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。换句话说,业务中使用SELECT语句的时候除了不可避免的搭配WHERE以外,还会配合ORDER BY进行使用。今天来好好聊聊 MySQL 的ORDER BY排序。排序算法说...

weixin_29323551的博客 234

【项目实战】主流车载操作系统,QNX实时操作系统入门介绍

QNX是一种实时操作系统,自1980年代初期由Quantum Software Systems成立以来,已被广泛应用于各种行业和领域。QNX具有实时响应、高可靠性和分布式等特点,为各种设备提供了强大的底层操作系统平台。随着科技的不断发展和进步,QNX系统的应用范围和潜力也在不断扩大。本文将全面介绍QNX系统,包括其引言、背景、系统特性、应用领域和生态系统等方面。QNX作为一种实时操作系统,具有高效的实时性能、高可靠性、分布式、可剪裁性和可扩展性等特点。它在各个领域都有广泛的应用,并拥有一个庞大的生态系统。

奶爸的编程之路,也就一周冷个三天 3071

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

mysql 排序 tmp_MySQL排序的艺术:你真的懂 Order By吗?

原标题:MySQL排序的艺术:你真的懂 Order By吗?MySQL排序的艺术:你真的懂 Order By吗? 前言业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。换句话说,业务中使用 SELECT语句的时候除了不可避免的搭配 WHERE以外,还会配合 ORDER BY进行使用。今天来好好聊聊 MySQL 的 ORDER BY排序。排序算法说到排序算法,有插入排序...

weixin_39574720的博客 182

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

mysql 链表排序_MySQL 排序的艺术:你真的懂 Order By 吗?

❝作者:宫水三叶。现微软工程师(Java 后端方向),退役 OIer。更多和 MySQL 面试 & 算法相关内容可点击「这里」关注~更好的阅读体验,请点击查看原文转载需关注公众号联系开白名单 ~❞前言业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。换句话说,业务中使用SELECT语句的时候除了不可避免的搭配WHERE以外,还会配合ORDER BY进行使用。...

weixin_42099942的博客 431

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

mysql排序保存_MySQL 排序的艺术:你真的懂 Order By 吗?

❝作者:宫水三叶。现微软工程师(Java 后端方向),退役 OIer。更多和 MySQL 面试 & 算法相关内容可点击「这里」关注~❞前言业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。换句话说,业务中使用 SELECT 语句的时候除了不可避免的搭配 WHERE 以外,还会配合 ORDER BY 进行使用。今天来好好聊聊 MySQL 的 OR...

weixin_39619858的博客 425

mysql帖子排序_MySQL排序的艺术:你真的懂 Order By 吗?

前言业务中的各种查询通常对应了用户所看到的各项列表,列表一般是根据某个维度进行排序。换句话说,业务中使用SELECT语句的时候除了不可避免的搭配WHERE以外,还会配合ORDER BY进行使用。今天来好好聊聊 MySQL 的ORDER BY排序。排序算法说到排序算法,有插入排序、选择排序、归并排序、堆排序、快速排序、计数排序、桶排序、基数排序、冒泡排序、希尔排序、梳排序 ...关于...

weixin_33132251的博客 167
上一篇: 源码阅读范例,终于有人把JDK源码精髓收录成册,全网开源了
下一篇: 阿里P8面试官一时疏忽就把最新80道JVM与多线程面试题给泄漏了
Java架构设计
博客等级 码龄5年 832粉丝 608原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值