7.2.4 【MySQL】匹配范围值

2023-09-19 09:13:10

回头看我们 idx_name_birthday_phone_number 索引的 B+ 树示意图,所有记录都是按照索引列的值从小到大的顺序排好序的,所以这极大的方便我们查找索引列的值在某个范围内的记录。比方说下边这个查询语句:

SELECT * FROM person_info WHERE name > 'Asa' AND name < 'Barlow';

由于 B+ 树中的数据页和记录是先按 name 列排序的,所以我们上边的查询过程其实是这样的:

找到 name 值为 Asa 的记录。

找到 name 值为 Barlow 的记录。

由于所有记录都是由链表连起来的(记录之间用单链表,数据页之间用双链表),所以他们之间的记录都可以很容易的取出来喽~

找到这些记录的主键值,再到 聚簇索引 中 回表 查找完整的记录。

不过在使用联合进行范围查找的时候需要注意,如果对多个列同时进行范围查找的话,只有对索引最左边的那个列进行范围查找的时候才能用到 B+ 树索引,比方说这样:

FROM person_info WHERE name > 'Asa' AND name < 'Barlow' AND birthday > '1980-01-01';

上边这个查询可以分成两个部分:

1. 通过条件 name > 'Asa' AND name < 'Barlow' 来对 name 进行范围,查找的结果可能有多条 name 值不同的记录,

2. 对这些 name 值不同的记录继续通过 birthday > '1980-01-01' 条件继续过滤。

这样子对于联合索引 idx_name_birthday_phone_number 来说,只能用到 name 列的部分,而用不到 birthday 列的部分,因为只有 name 值相同的情况下才能用 birthday 列的值进行排序,而这个查询中通过 name 进行范围查找的记录中可能并不是按照 birthday 列进行排序的,所以在搜索条件中继续以 birthday 列进行查找时是用不到这个 B+ 树索引的。

7.2.5 精确匹配某一列并范围匹配另外一列

对于同一个联合索引来说,虽然对多个列都进行范围查找时只能用到最左边那个索引列,但是如果左边的列是精确查找,则右边的列可以进行范围查找,比方说这样:

SELECT * FROM person_info WHERE name = 'Ashburn' AND birthday > '1980-01-01' AND birthd

这个查询的条件可以分为3个部分:

1. name = 'Ashburn' ,对 name 列进行精确查找,当然可以使用 B+ 树索引了。

2. birthday > '1980-01-01' AND birthday < '2000-12-31' ,由于 name 列是精确查找,所以通过 name ='Ashburn' 条件查找后得到的结果的 name 值都是相同的,它们会再按照 birthday 的值进行排序。所以此时对 birthday 列进行范围查找是可以用到 B+ 树索引的。

3. phone_number > '15100000000' ,通过 birthday 的范围查找的记录的 birthday 的值可能不同,所以这个条件无法再利用 B+ 树索引了,只能遍历上一步查询得到的记录。

同理,下边的查询也是可能用到这个 idx_name_birthday_phone_number 联合索引的:

SELECT * FROM person_info WHERE name = 'Ashburn' AND birthday = '1980-01-01' AND AND p

7.2.6 用于排序

在写查询语句的时候经常需要对查询出来的记录通过 ORDER BY 子句按照某种规则进行排序。一般情况下,我们只能把记录都加载到内存中,再用一些排序算法,比如快速排序、归并排序等等在内存中对这些记录进行排序,有的时候可能查询的结果集太大以至于不能在内存中进行排序的话,还可能暂时借助磁盘的空间来存放中间结果,排序操作完成后再把排好序的结果集返回到客户端。在 MySQL 中,把这种在内存中或者磁盘上进行排序的方式统称为文件排序(英文名: filesort ),跟 文件 这个词儿一沾边儿,就显得这些排序操作非常慢了(磁盘和内存的速度比起来,就像是飞机和蜗牛的对比)。但是如果 ORDER BY 子句里使用到了我们的索引列,就有可能省去在内存或文件中排序的步骤,比如下边这个简单的查询语句:

SELECT * FROM person_info ORDER BY name, birthday, phone_number LIMIT 10;

这个查询的结果集需要先按照 name 值排序,如果记录的 name 值相同,则需要按照 birthday 来排序,如果birthday 的值相同,则需要按照 phone_number 排序。大家可以回过头去看我们建立的idx_name_birthday_phone_number 索引的示意图,因为这个 B+ 树索引本身就是按照上述规则排好序的,所以直接从索引中提取数据,然后进行 回表 操作取出该索引中不包含的列就好了。

7.2.6.1 使用联合索引进行排序注意事项

对于 联合索引 有个问题需要注意, ORDER BY 的子句后边的列的顺序也必须按照索引列的顺序给出,如果给出ORDER BY phone_number, birthday, name 的顺序,那也是用不了 B+ 树索引,这种颠倒顺序就不能使用索引的。

同理, ORDER BY name 、 ORDER BY name, birthday 这种匹配索引左边的列的形式可以使用部分的 B+ 树索引。当联合索引左边列的值为常量,也可以使用后边的列进行排序,比如这样:

SELECT * FROM person_info WHERE name = 'A' ORDER BY birthday, phone_number LIMIT 10;

这个查询能使用联合索引进行排序是因为 name 列的值相同的记录是按照 birthday , phone_number 排序的。

7.2.6.2 不可以使用索引进行排序的几种情况

ASC、DESC混用

对于使用联合索引进行排序的场景,我们要求各个排序列的排序顺序是一致的,也就是要么各个列都是 ASC 规则排序,要么都是 DESC 规则排序。

想想这个 idx_name_birthday_phone_number 联合索引中记录的结构:

先按照记录的 name 列的值进行升序排列。

如果记录的 name 列的值相同,再按照 birthday 列的值进行升序排列。

如果记录的 birthday 列的值相同,再按照 phone_number 列的值进行升序排列。

如果查询中的各个排序列的排序顺序是一致的,比方说下边这两种情况:

ORDER BY name, birthday LIMIT 10

这种情况直接从索引的最左边开始往右读10行记录就可以了。

ORDER BY name DESC, birthday DESC LIMIT 10 ,

这种情况直接从索引的最右边开始往左读10行记录就可以了。

但是如果我们查询的需求是先按照 name 列进行升序排列,再按照 birthday 列进行降序排列的话,比如说这样的查询语句:

SELECT * FROM person_info ORDER BY name, birthday DESC LIMIT 10;

这样如果使用索引排序的话过程就是这样的:

先从索引的最左边确定 name 列最小的值,然后找到 name 列等于该值的所有记录,然后从 name 列等于该值的最右边的那条记录开始往左找10条记录。

如果 name 列等于最小的值的记录不足10条,再继续往右找 name 值第二小的记录,重复上边那个过程,直到找到10条记录为止。

WHERE子句中出现非排序使用到的索引列

如果WHERE子句中出现了非排序使用到的索引列,那么排序依然是使用不到索引的,比方说这样:

SELECT * FROM person_info WHERE country = 'China' ORDER BY name LIMIT 10;

这个查询只能先把符合搜索条件 country = 'China' 的记录提取出来后再进行排序,是使用不到索引。注意和下边这个查询作区别:

SELECT * FROM person_info WHERE name = 'A' ORDER BY birthday, phone_number LIMIT 10;

虽然这个查询也有搜索条件,但是 name = 'A' 可以使用到索引 idx_name_birthday_phone_number ,而且过滤剩下的记录还是按照 birthday 、 phone_number 列排序的,所以还是可以使用索引进行排序的。

排序列包含非同一个索引的列

有时候用来排序的多个列不是一个索引里的,这种情况也不能使用索引进行排序,比方说:

SELECT * FROM person_info ORDER BY name, country LIMIT 10;

name 和 country 并不属于一个联合索引中的列,所以无法使用索引进行排序。

排序列使用了复杂的表达式

要想使用索引进行排序操作,必须保证索引列是以单独列的形式出现,而不是修饰过的形式,比方说这样:

SELECT * FROM person_info ORDER BY UPPER(name) LIMIT 10;

使用了 UPPER 函数修饰过的列就不是单独的列,这样就无法使用索引进行排序。

更多推荐

可视化大屏报表的设计与制作 | 附成果图

大屏可视化报表是一种以大屏幕为展示媒介,通过图形、图表、文字等多种方式将数据信息呈现出来的报表形式。它具有视觉冲击力强、信息量大、交互性高等特点,能够帮助企业快速获取数据背后的价值和洞见,提高决策效率。因此近年来,大屏可视化报表越来越受企业青睐。然而,大屏可视化报表的设计与制作并非易事,需要克服诸多难点和挑战。例如,如

pytroch 颜色增强ColorJitter,墙裂推荐

目录函数参数解释:随机亮度测试,非常方便,墙裂推荐:单项测试:举例:yolov5颜色增强示例,效果差不多,opencv的:函数参数解释:函数名:torchvision.transforms.ColorJitter(brightness=0,contrast=0,saturation=0,hue=0)函数解析:随机改变一

2023华为杯E题:出血性脑卒中临床智能诊疗建模

文章目录一、背景介绍二、数据集介绍及建模目标第一题:血肿扩张风险相关因素探索建模。第一问第二问第二题:血肿周围水肿的发生及进展建模,并探索治疗干预和水肿进展的关联关系第一问第二问第三问第四问第三题:出血性脑卒中患者预后预测及关键因素探索第一问第二问第三问附件代码免费获取方式一、背景介绍一堆介绍,了解下我们为何要做这个研

企业电子招标采购系统源码之从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理

功能描述1、门户管理:所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含:招标公告、非招标公告、系统通知、政策法规。2、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看所有的立项信息。主要功能包含:招标立项申请、非招标立项申请、采购立项管理。3、采购项目管理:可对项目采购过程全流程管

HCL Domino LEAP与新的软件下载门户站点

大家好,才是真的好。还记得DominoVolt吗?是的,我前面花了不少时间来讲基于Domino平台上的低代码开发工具Volt,不下十篇,我记得最后一篇是《DominoVolt1.0.5中的可视化流程设计器》。结果就在去年11月,HCL将该该工具重新命名为HCLDominoLeap,可能是为了避免和HCL最近热推的Vol

【工作】-处理快速切换 Tab 导致列表数据不正确的情况

采取以下方案来解决:取消之前的请求:在切换到新的Tab之前,首先检查是否有之前的请求正在进行中。如果是,可以使用取消请求的机制中止之前的请求,以确保不会更新当前Tab的数据。你可以使用类似Axios提供的canceltoken来取消请求。防止并发请求:为了避免并发请求导致数据不正确,你可以在发起新请求之前添加一个标记来

视觉设计师提升自己能力的经验优漫动游

1、业余时间视觉设计师提升自己能力的经验还经常听到一种抱怨”产品有限制,我所擅长发挥不出来”,这样无疑是把自己的设计专业成长寄托在产品上。认为产品不成功自己的设计就不能成长。这其实是个借口。其实面对这个问题,最好的办法就是把设计分2条线:1.项目线:公司的实际产品项目,理解并按照实际情况,满足产品设计需求并达到公司要求

Flask框架-2-[单聊]: flask-socketio实现websocket的功能,实现单对单聊天,flask实现单聊功能

一、概述和项目结构在使用flask-socketio实现单聊时,需要将会话id(sid)与用户进行绑定,通过emit('事件','消息',to=sid),就可以把消息单独发送给某个用户了。flask_websocket|--static|--js|--jquery-3.7.0.min.js|--socket.io_4.

基于STM32设计的校园一卡通(设计配套的手机APP)

一、功能介绍【1】项目介绍随着信息技术的不断发展,校园一卡通作为一种高效便捷的管理方式,已经得到了广泛的应用。而其核心部件——智能卡也被越来越多的使用者所熟知。本文介绍的项目是基于STM32设计的校园一卡通消费系统,通过RC522模块实现对IC卡的读写操作,利用2.8寸TFT触摸屏(驱动芯片是ILI9341)作为交互界

【自学开发之旅】Flask-前后端联调-异常标准化返回(六)

注册联调:前端修改:1.修改请求向后端的url地址文件:env.development修改成VITE_API_TARGET_URL=http://127.0.0.1:9000/v1登录:token验证校验forms/user.pyfromwerkzeug.securityimportcheck_password_has

redis漏洞修复:(CNVD-2019-21763)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、漏洞内容二、镜像准备1.确认镜像版本2.下载镜像三、配置文件准备1.获取配置文件2.修改配置文件四、启动redis容器五、修改iptables文件总结前言漏扫发现机器上基于容器运行的redis的访问权限没有限制,需要增加安全配置。现在使用的

热文推荐