关于在 MySQL 排序中使用索引这件事!

news2024/11/15 20:21:30

文章目录

    • 1. 排序的两种方式
    • 2. 索引排序
      • 2.1 案例一
      • 2.2 案例二
      • 2.3 案例三
      • 2.4 案例四
      • 2.5 案例五
      • 2.6 案例六
      • 2.7 案例七
      • 2.8 案例八
    • 3. 其他情况
      • 3.1 多表联查
      • 3.2 order by null
    • 4. 小结

前面跟小伙伴们分享的索引相关的内容,基本上都是在 where 子句中使用索引,实际上,索引也还有另外一个大的用处,那就是在排序中使用索引,今天我们就来聊聊这个话题。

1. 排序的两种方式

MySQL 中想给查询结果排序,我们只需要来一个 order by 即可,SQL 很简单,底层实现起来整体上来说,有两种不同的思路:

  1. filesort,有时候我们也将之称为文件排序,这个名字有时候会给我们一些误解,让人以为是在磁盘上进行排序的,然而实际上并不一定,数据量比较小的时候,直接在内存中进行排序就行了,只有当在内存中无法完成排序的时候,才会用到磁盘文件。
  2. 索引排序,由于 InnoDB 中的索引是按照 B+Tree 的形式将数据组织在一起的,B+Tree 中数据本身就是有序的,所以如果能够利用好索引,排序的事情就会事半功倍。

一共就这两种排序的方式,小伙伴们也发现了,如果我们的索引设计比较合理,最终能够按照第 2 种方式进行排序,那肯定是最好不过了。

不过这里需要注意一个细节,第二种排序方式快有一个前提,那就是不需要回表,如果查询的过程中需要回表,那么第二种方式就不一定快了。原因也简单:

  • 如果不需要回表,也就是我们想要查询的数据都在索引树上,索引树上的数据本身又都是按照顺序存储的,那么查到数据直接返回即可,本身就是有序的。
  • 如果查询的时候,索引树上并没有我们想要的字段,那么就需要回表,小伙伴们知道,回表基本上都是随机 IO 了,因为回表的时候,主键值并不一定连续,此时效率就会低一些。那么这个时候第二种排序方式的性能就不一定强于第一种了,当然,这并无固定结论,还是要结合具体情况分析,这里我只是告诉小伙伴们有各种可能的情况。

2. 索引排序

如果我们想用上索引排序,那么需要满足哪些条件呢?

还是以我们上篇文章的数据为例,假设我有如下表结构:

CREATE TABLE `user` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `age` int DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `gender` varchar(2) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `user_prop_index` (`username`,`age`,`address`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

这个表中有一个联合索引,联合索引的字段包含 username、age 和 address 三个。

表中的数据如下:

id(主键)usernameageaddressgender
1ab99深圳
2bw95天津
3cx93深圳
4bc80上海
5bg85重庆
6ac98广州
7bw99海口
8ck90深圳
9cc92武汉
10af88北京

还是假设 username、age、address 三个字段组成联合索引,B+Tree 如下:

小伙伴们就想想,怎么样查询,查出来的结果是有序的?

给大家 1 分钟总结一下。

我们来梳理下:只有当索引的顺序和 order by 子句的顺序完全一致,并且所有列的排序方向也都一致的情况下,MySQL 才能通过索引来对结果进行排序,同时,如果是联合索引,order by 子句也需要满足最左匹配原则。

我举几个例子。

2.1 案例一

先来看如下 SQL:

select address from user order by username;

这个是查询 address 字段,根据 username 进行排序。很明显,我们想要的 address 字段就存在于这个联合索引的 B+Tree 上,并且这个联合索引的 B+Tree 就是按照 username 进行升序排序的,所以这个 SQL 就可以通过索引进行排序,如下图:

type:index 就说明了 MySQL 使用了索引扫描来进行排序的。

2.2 案例二

再来看下面这条 SQL:

select address from user order by username asc,age desc\G

这个 SQL 还是查询 address 字段,是根据 username 和 age 进行排序的,其中 username 是按照升序排序,age 则是按照倒序排序,小伙伴们想想,在前面这个联合索引的 B+Tree 中,username 是升序的没问题,当 username 相同的时候,age 也是按照升序排序的,但是 SQL 中却要一个升序一个倒序,显然从索引树中拿到的数据无法满足这样的条件,所以这个查询并不会使用索引排序,如下图:

Extra 中的 Using filesort 就说明了这里需要文件排序,无法通过索引排序完成需求。

2.3 案例三

再来看如下 SQL:

select address from user order by username desc

这个 SQL 和 2.1 小节的 SQL 相比就是排序的顺序变了,第一个 SQL 没有写顺序,默认就是升序,这个里边写了是按照倒序来排列。B+Tree 中的 username 是升序,那么这个能用到索引排序吗?这个是可以使用到索引排序的,在 MySQL5.7 中,执行计划如下:

在 MySQL8.x 中,执行计划如下:

小伙伴们看到,区别在于 Extra 中多了一个 Backward index scan

这是啥意思呢?

在 MySQL8 之前,索引是可以被反向扫描的,但是反向扫描效率会低一些,所以小伙伴们看到,在 MySQL5.7 中用到了索引排序,而且也没说其他的,这其实就是索引反向扫描了。

从 MySQL8 开始,索引定义时候的降序关键字 DESC 将不再被忽略,索引树在存储数据的时候可以降序存储了,这样在将来查询的时候扫描索引就可以按照正向扫描了,正向扫描效率相对于反向扫描效率会高一些。

这块我来举个例子说明问题。假设我有如下创建表的 SQL:

CREATE TABLE t (
  c1 INT, c2 INT,
  INDEX idx1 (c1 ASC, c2 ASC),
  INDEX idx2 (c1 ASC, c2 DESC),
  INDEX idx3 (c1 DESC, c2 ASC),
  INDEX idx4 (c1 DESC, c2 DESC)
);

当我在 MySQL5.7 中执行如上 SQL 之后,再来查看表的定义,结果如下:

可以看到,虽然我在执行的时候定了索引字段的顺序,但是这个顺序实际上是被忽略了。

再来看看 MySQL8 中执行之后的结果:

可以看到,在 MySQL8 中,索引定义时字段的顺序被保留了。这印证了我们前面所说的没有问题。

最后,回到我们的问题,Backward index scan 表示优化器在查询的时候将能够使用降序索引。

2.4 案例四

再来看如下 SQL:

select gender from user where username='ab' order by age

这个 SQL 中已经给 username 指定了具体的值了,在前面的 B+Tree 中,当 username 已经确定的时候,那么接下来就是按照 age 排序的,如果 age 相同则是按照 address 排序,所以上面这个 SQL 是可以通过索引排序的:

2.5 案例五

再来看如下 SQL:

select gender from user where username='ab' order by address

这个 SQL 中 username 也是给指定了具体的值了,但是排序却是按照 address 排序的,小伙伴们知道,当 username 确定后,首先是按照 age 排序,其次才是按照 address 排序,所以,对于上面这个 SQL,从索引树中读取出来的数据,顺序并不一定是按照 address 排的,所以上面这个 SQL 无法用到索引排序:

2.6 案例六

再来看下面这个 SQL:

select gender from user where username like 'a%' order by age

这个 SQL 中的查询条件 username 是范围搜索,当 username 是范围搜索的时候,就无法保证相应的 age 是有序的了,所以这个 SQL 也无法使用索引排序:

另外需要注意的是,像查询条件中的 IN 和 BETWEEN 这样的关键字,也算是范围搜索,如果 where 子句中出现这些关键字,也是有可能导致无法使用索引排序的。

2.7 案例七

再来看下面这个 SQL:

select gender from user where username like 'a%' order by username,age

这个虽然 username 也是按照范围搜索,但是最终排序的时候却是按照 username 和 age 排序的,按照范围搜索拿出来的 username 和 age 本身就是有序的,所以这里也可以使用索引排序:

2.8 案例八

再来看下面这个 SQL:

select gender from user where username like 'a%' order by username,gender

这个 SQL 就不用多说了,排序字段中出现了索引之外的列,那肯定没法使用索引排序了:

总之,就是当我们根据 where 子句中的条件从 B+Tree 中定位到数据之后,定位到的这个数据究竟是否有序?如果有序且是 SQL 中要求的顺序,就能使用索引排序,否则就不可以。

现在我们再来回过头看一下一开始的结论,大家这个时候应该就好理解了:

只有当索引的顺序和 order by 子句的顺序完全一致,并且所有列的排序方向也都一致的情况下,MySQL 才能通过索引来对结果进行排序,同时,如果是联合索引,order by 子句也需要满足最左匹配原则。

3. 其他情况

3.1 多表联查

当我们在查询的时候是多表连接查询时,如果用到了排序,那么 order by 子句中涉及到的字段,必须全部在第一个表中,此时才会用到索引排序。

松哥举一个 TienChin 项目中的例子,TienChin 中有一个活动渠道表 tienchin_channel,还有一个活动表 tienchin_activity,活动表中引用到了渠道表的 id,我们来做如下一个多表联合查询:

select ta.name from tienchin_activity ta inner join tienchin_channel tc using(`channel_id`)

我们来看下这个 SQL 的执行计划:

可以看到,在这个查询中,优化器将 ta 表作为了第一张表,tc 表作为了第二张表,那么根据前面的结论,如果使用第一个表中的索引排序,就会用到索引排序,第二张表的则用不了,我们来验证一下。

可以看到,如果是第一张表的索引,就用到了索引排序;如果是第二张表的索引,就没有用到索引排序,如果两张表的索引都用了,也不会使用索引排序。

3.2 order by null

还有一种特殊的情况就是 order by null,不知道有没有小伙伴见到过有人这样写?

在 MySQL8 之前,默认会按照 group by 的字段进行排序,此时加上 order by null 就是告诉 MySQL,不用帮我排序了,直接返回结果就行了,因为如果不加 order by null,则可能会进行 filesort 排序,降低查询效率。

不过从 MySQL8 开始,默认已经不会按照 group by 字段排序了,所以这句现在其实可以不用写了。

4. 小结

好啦,关于 MySQL 中的索引排序就和小伙伴们聊这么多,希望大家都有所收获~

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

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

相关文章

java环境变量 的配置与详解

笔者这学期开始学习java课程,学习java开发首先需要配置java运行环境变量。虽然上课老师也讲了如何配置java环境变量,可是笔者的同学还是有好多都不会配置,所以笔者最近配置了特别多次java环境变量。如下笔者详细解释从JDK安装到环境变量的装配…

rsync本地或远程备份

这里写自定义目录标题 rsync作用rsync用法scp /cp/rsync区别ssh无密码登陆原理远程备份案例远程备份脚本脚本1:脚本2 本地备份常用参数 rsync作用 实现本地或远程 全量备份 增量备份 rsync用法 rsync -avz 本机文件夹 远程主机用户名IP:远程主机文件夹 scp /cp/…

发电厂能源管理远程监控解决方案

发电厂能源管理远程监控解决方案 项目背景 在我国经济快速发展的同时,对用电的要求也越来越高。为了节约能源和降低成本,国家正在积极推动发电厂的技术改造。发电厂作为发电企业的核心,其耗能状况关系到整个国家的经济发展。为进一步加强对电…

如何成为一名职业黑客?

我需要什么技能才能成为一名优秀的专业黑客?” 由于黑客是最熟练的信息技术学科之一,它需要广泛的 IT 技术和技巧知识。要真正成为一名真正的黑客,必须掌握许多技能。这是我总结所需技能的概述列表。我将这些技能分为三类,以帮助你…

家用洗地机有什么推荐的吗?好用的家用洗地机

洗地机采用高效能滚刷设计,可轻松处理多种不同材质地面的卫生问题,例如:地毯、硬地板、瓷砖等等,都能轻松完成深度清洁。而且洗地机还具有智能化设计,例如自动充电、一键启动和一键停止等设计,使它操作起来…

【Hello Algorithm】基础数据结构

作者:小萌新 专栏:算法 作者简介:大二学生 希望能和大家一起进步 本篇博客简介:介绍几种基础数据结构 基础数据结构 单链表结构翻转单链表删除节点 双链表栈和队列用栈实现队列用队列实现栈 哈希表 单链表结构 在阅读这篇文章之前…

GLM-130B-一个开放的双语通用预训练模型-论文精读

本文为作为类ChatGPT的模型ChatGLM的前期基础论文2《AN OPEN BILINGUAL PRE-TRAINED MODEL》的精读笔记,基础论文1的精读笔记请见《GLM论文精读-自回归填空的通用语言模型》。希望对大家有帮助,欢迎讨论交流。GLM-130B,主要思想概述&#xff…

Android 签名文件

签名文件相关 一、为什么需要签名?二、创建签名文件2.1、使用AS新建签名文件2.2、使用 keytool 新建签名文件 三、签名串改参考地址 一、为什么需要签名? Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中,也就是…

YooAsset | Unity资源管理方案

跳转官方仓库地址 一、说明 可空包、可首包DLC、可满足限制包体的需求、可玩家自己制作MOD上传到服务器、可分工程构建;支持内置渲染管线、可编程渲染管线;支持完整路径、可寻址资源定位;基于标签打包,自动分析冗余,基…

MongoDB 查询文档中使用$expr、$where选择器

之前我们介绍过使用比较选择器、逻辑选择器、元素选择器、数组选择器查询文档,如果您需要进一步了解,可以参考: MongoDB 查询文档中使用比较选择器、逻辑选择器https://blog.csdn.net/m1729339749/article/details/129965699MongoDB 查询文档…

【Ubuntu20.04】ROS noetic的g2o与系统g2o冲突问题

文章目录 0.问题描述1.问题原因2.解决方法2.1.方法12.1.方法2 3.成功效果 0.问题描述 \qquad 从github安装2023版本的g2o时,若ROS也安装了g2o,则会在编译时触发运行时冲突。具体表现为段错误,如若需要排查是否为ROS的g2o导致,则需…

MySQL:存储过程与函数、视图

一、学习目标 掌握如何创建存储过程掌握如何创建存储函数熟悉变量的使用方法熟悉如何定义条件和处理程序了解光标的使用方法掌握流程控制的使用掌握如何调用存储过程和函数熟悉如何查看存储过程和函数掌握修改存储过程和函数的方法熟悉如何删除存储过程和函数掌握创建存储过程…

知识推理——CNN模型总结(一)

记录一下我看过的利用CNN实现知识推理的论文。 最后修改时间:2023.05.12 目录 1.ConvE 1.1.解决的问题 1.2.优势 1.3.贡献与创新点 1.4.方法 1.4.1 为什么用二维卷积,而不是一维卷积? 1.4.2.ConvE具体实现 1.4.3.1-N scoring 1.5.…

TiDB x CAPCOM | 为在线游戏提供灵活、可靠、可扩展的数据库服务

通过 TiDB 连接全球极限场景和创新场景,是 PingCAP 长期坚持的国际化战略。目前,在全球已有超过 3000 家企业选择 TiDB。无论在游戏、金融、物流、互联网还是智能制造等行业,基于规模化 OLTP 扩容、实时 HTAP 分析等应用场景,Ping…

在idea工具下,使用protobuf自动生成java代码,超详细教程

新项目需要使用google protobuf 生成java代码 开始第一步,网上很多教程都说下载protobuf support插件,但是我下载了很多idea版本,就是找不到这个protobuf support 插件 在idea 中选择file ->settings ->plugin , 搜索protobuf,一般都…

[SWPUCTF] 2021新生赛之Crypto篇刷题记录(11)

[SWPUCTF] 2021新生赛之Crypto篇刷题记录① [SWPUCTF 2021 新生赛]crypto6[SWPUCTF 2021 新生赛]ez_caesar[SWPUCTF 2021 新生赛]crypto10[SWPUCTF 2021 新生赛]pigpig[SWPUCTF 2021 新生赛]traditional NSSCTF平台:https://www.nssctf.cn/ PS:记得所有…

渤海银行有点火,李伏安有点烦

文丨新熔财经 作者丨向雪徊 5月8日,大连银保监局连开七份罚单,处罚对象为渤海银行股份有限公司大连分行及相关责任人。 大银保监罚决字〔2023〕27号显示,渤海银行大连分行存在五项主要违法事实:一是未执行统一授信;…

【敬伟ps教程】套索、魔棒工具、快速选择工具、选区的编辑和调整

文章目录 套索工具自由套索多边形套索磁性套索工具 魔棒工具快速选择工具选区的编辑和调整 套索工具 自由套索 套索工具的用法,点击鼠标左键拖动鼠标建立选区。当选区没闭合时,松开鼠标会自动闭合选区。套索工具灵活快速但不够准确。套索工具的选项栏是…

拥有Type-C接口的显示器上 绝大多数人都不知这么大作用

大多数的数码爱好者认识Type-C接口,估计都是从2015年的安卓手机开始的。 但估计不少用户不知道的是,电脑端的显示器上也有Type-C接口。 如果你是一个刚入门想买显示器的朋友,下面可以分别看看显示器最常见的几种接口的介绍,结合你…

Sentinel 入门使用

目录 一. Sentinel简介1.1Sentinel简介1.2 Sentinel与Hystrix的区别1.3 名词解释 二. sentinel控制台2.1 下载启动控制台2.3 客户端接入控制台2.4 Rest整合Sentinel2.5 Feign 整合Sentinel 想了解Sentinel具体的使用规则就点这里呀!!! 一. Se…