当前位置: 首页 > news >正文

联合索引最左前缀原则原理索引下推

联合索引

联合索引依旧是辅助索引的一种情况 (不是主键索引就都归属于辅助索引)辅助索引可以在多个字段之间建立,如果第一个字段相同则比较第二个字段,依次类推建立索引搜索树结点之间的先后关系,也就是说索引项按照索引定义的字段顺序排序 (后面要讲到的最左前缀原则就是在此基础上来分析的) ,下面举个例子,建立name_age的联合索引

create table T(`id` int primary key,`name` varchar(11) not null,`age` int not null,key `name_age` (`name`, `age`)
) # 5.5以后默认是InnoDB存储引擎
# 插入了四条数据:(1, 小红, 16)、(2, 小红, 15)、(3, 小兰, 16)、(4, 小金, 16)

在这里插入图片描述

下面给出一条针对这个name_age的联合索引的查询语句

select id from T where name = '小红' and age = 15 
-- 通过上一篇学习索引覆盖的知识点,你应该能分析出这条sql只会搜索右边的联合索引树,获得到id之后不需要再去回表搜索主键索引树

最左前缀原则

从本质上来说,联合索引也是一棵 B+ 树,不同的是联合索引的键值的数量不是 1,而是大于等于 2。我们来看下两个整型列组成的联合索引,假定两个键值的名称分别为 a、b

在这里插入图片描述

从图中可以看到多个键值的 B+ 树情况,键值都是排序的。通过叶子节点可以逻辑上顺序读取所有数据,就上面图中所示,即为 (1,1)、(1、2)、(2、1)、(2、4)、(3、1)、(3、2),数据是按照 (a, b) 的顺序进行存放。

这里 “**键值都是排好序” 的这种说法可能会让大伙很疑惑,**似乎只有 a 列是排序的,b 列并没有排序啊。

注意!这里的排序,意思是确定了第一个键,对于第一个键相同的记录来说,查询的结果是对第二个键进行了排序

这也是**使用联合索引的第二个好处,即已经对第二个键值进行了排序处理,可以避免多一次排序操作。**举个例子:有些应用程序都需要查询某个用户的购物情况,并按照时间进行排序,取出最近 n 次的购买记录,这时使用联合索引就可以避免多一次排序操作,因为索引本身在叶子节点已经排序了。

更进一步说,假设有联合索引(a,b,c),下列语句可以直接通过联合索引得到结果:

  • SELECT ... FROM TABLE WHERE a=xxx ORDER BY b
  • SELECT ... FROM TABLE WHERE a=xxx AND b=xxx ORDER BY c

但是对于下面的语句,联合索引不能直接得到结果,其还需要执行一次排序操作,因为索引 (a,c) 并未排序:

  • SELECT ... FROM TABLE WHERE a=xxx ORDER BY c

考虑下,对于下面这条语句,能否用到联合索引(a, b)?

select * from table where a = XXX and b= XXX;
# 这个当然没问题。

那对于 a 列的单独查询,能否用到联合索引(a, b)?

select * from table where a = XXX;
# 当然也可以,我们不是说了,a 列是已经排好序的

但是对于 b 列的单独查询则不能使用联合索引(a, b)!

select * from table where b = XXX;
# b 列的单独查询则不能使用联合索引(a, b)

因为把叶子节点中的 b 值单独拎出来看它不是有序的:1、2、1、4、1、2,因此对于 b 的查询是使用不到 (a,b) 这个联合索引的。

同样的道理,对于(a, b, c)联合索引来说,查询 (a, b) 可以用到这个联合索引,但是查询 (b, c) 就没办法使用这个联合索引,因为 b 和 c 列的有序性都是依托于 a 列的存在的

就是联合索引的最左前缀原则,只要查询的是联合索引的最左 N 个字段,就可以利用该联合索引来加速查询

我们来讨论一个问题:在建立联合索引的时候,如何安排索引内的字段顺序

有两点原则。

首先,第一原则,如果通过调整顺序,可以少维护一个索引,那么这个字段顺序往往就是需要优先考虑采用的

很好理解,当已经有了 (a,b) 这个联合索引后,一般就不需要单独在 a 上建立索引了。

那么,再思考一个问题:如果既有联合查询 (a,b),又有基于 a、b 各自的查询呢?

显然,如果查询条件里面只有 b 的语句,是无法使用 (a,b) 这个联合索引的,这时候你不得不维护另外一个 b 列的索引,也就是说你需要同时维护 (a,b)、(b) 这两个索引。

举个用户表例子,有这样三个高频查询需求:

  • 根据 name 查询 id:select id from user where name = xxx;
  • 根据 age 查询 id:select id from user where age= xxx;
  • 根据 name 和 age 查询 id:select id from user where name = xxx and age = xxx;

这个时候,我们有两种索引建立的选择:

  1. 联合索引 (age, name) + 单字段索引 (name)
  2. 联合索引 (name, age) + 单字段索引 (age)

怎么选?

这种场景下,我们要考虑的原则就是空间

显然,name 字段是要比 age 字段大的,所以,第二种选择占用的空间要小于第一种选择,推荐大伙儿使用第二种选择:联合索引 (name, age) + 单字段索引 (age)


索引下推

最左前缀可以用于在索引中定位记录,那么,那些不符合最左前缀的部分,会怎么样呢?

以用户表的联合索引(name, age)为例,假设现在有一个需求,找出所有姓 “张” 并且 20 岁的男性:

select * from tuser where name like '张%' and age = 20 and sex = male

《高性能 MySQL》 书中提到:对于联合索引,如果查询中有某个列的范围查询,则其右边所有列都无法使用索引进行快速定位

解释:因为满足name like '张%'的记录可能有多条,而age字段的有序是建立的name有序的基础之上,比如数据有 (张三, 15) (张四, 16) (张五, 17) (张六, 16),单独看age字段之间是无序的,因此在满足条件的name字段是多个的时候,age字段的索引就丧失功能了,只有当name字段匹配的结果唯一,age字段的有序才有意义

所以对于这条语句来说,其实并不能完全踩中 (name, age) 这个联合索引,他只能踩到 name。

具体来说,这个语句在搜索(name,age)的联合索引树的时候,并不会去看 age 的值,只是按顺序把 “name 第一个字是张” 的记录一条条取出来,然后开始回表,到主键索引上找出数据行,再一个一个判断其他条件是否满足。从下图可以看出来,需要回表 3 次。

在这里插入图片描述

这是 MySQL 5.6 之前的做法,简单总结,当进行索引查询时,首先根据索引来查找记录,然后再根据 where 条件来过滤记录

而 MySQL 5.6 开始,数据库在取出索引的同时,会根据 where 条件直接过滤掉不满足条件的记录,减少回表次数。这就是 索引下推 (Index Condition Pushdown,ICP) ,一种根据索引进行查询的优化方式

在这里插入图片描述

从图中可以看出来,InnoDB 在 (name,age) 索引内部就判断了 age 是否等于 20,对于不等于 20 的记录,直接判断并跳过,所以只需要对 ID1 这条记录进行回表判断就可以了。

总结:

索引下推:MySQL5.5以及之前的版本中,在满足范围匹配name like '张%'之后,并不会继续判断后面个age字段,直接就回表了,而从MySQL5.6开始,InnoDB存储引擎在匹配到满足name like '小%'之后,无法继续使用最左前缀原则的字段(如本例的age)依旧在联合索引中,则会根据这些字段多做一些过滤,不满足条件的记录将不会回表查询,减少了二次搜索的次数。


文章转载自:

http://EBLxlps5.mfcbk.cn
http://1vWGQfVq.mfcbk.cn
http://D0Irbbrn.mfcbk.cn
http://ZMcROZxi.mfcbk.cn
http://sg0I9zsa.mfcbk.cn
http://UqUk17tn.mfcbk.cn
http://r1SI9U3j.mfcbk.cn
http://dYcaniQu.mfcbk.cn
http://MNtoC2w9.mfcbk.cn
http://hqd1bGTI.mfcbk.cn
http://2ETAmXRk.mfcbk.cn
http://yX1HSSrG.mfcbk.cn
http://8X6q4YFJ.mfcbk.cn
http://iv82lnaj.mfcbk.cn
http://sS4EeTpZ.mfcbk.cn
http://426vC2sV.mfcbk.cn
http://zpRKflpO.mfcbk.cn
http://kmGb0Ri0.mfcbk.cn
http://2GkXbb8S.mfcbk.cn
http://zoHp7Xvi.mfcbk.cn
http://aUAyZKNI.mfcbk.cn
http://JJSVzdRf.mfcbk.cn
http://egD8ykip.mfcbk.cn
http://3ywVP1U6.mfcbk.cn
http://9knFAj7i.mfcbk.cn
http://GPHDPcZm.mfcbk.cn
http://tYKhA0BT.mfcbk.cn
http://HxPnFMWg.mfcbk.cn
http://0rGE7zpP.mfcbk.cn
http://m9MS6IHg.mfcbk.cn
http://www.dtcms.com/a/378487.html

相关文章:

  • 平衡车 -- 速度环
  • BPE算法深度解析:从零到一构建语言模型的词元化引擎
  • DIPMARK:一种隐蔽、高效且具备鲁棒性的大语言模型水印技术
  • mysql多表联查
  • 审美积累 | 移动端仪表盘
  • 面阵结构光3D相机三维坐标计算
  • 【大前端++】几大特征
  • 【持续更新】高质量的项目开发过程(C++)(前后端)
  • 淘宝商品视频批量自动化获取的常见渠道分享
  • ABAP 将多层json逐层解析转成内表
  • 一样的糖果
  • linux x86_64中打包qt
  • Windows 10 22H2 64位 【原版+优化版、版本号:19045.6332】
  • 学习日记-CSS-day53-9.11
  • 线程的创建.销毁
  • pg卡死处理
  • 装饰器模式在Spring中的案例
  • 【Springboot】介绍启动类和启动过程
  • 服务器内部信息获取
  • 软考 系统架构设计师系列知识点之杂项集萃(143)
  • BFD原理与配置
  • spring源码分析————ListableBeanFactory
  • InfoSecWarrior CTF 2020: 02靶场渗透
  • wikijs如何增加全文搜索的功能,增加对应的索引(Win11环境+docker+数据库elasticSearch)
  • 企业远程访问方案选择:何时选内网穿透,何时需要反向代理?
  • go中的singleflight是如何实现的?
  • 计算机毕业设计 基于Hadoop的南昌房价数据分析系统的设计与实现 Python 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试
  • 在Cursor里安装极其好用的Mysql Database Client 插件
  • C# .NET EFCore 性能优化
  • STM32--时间戳,BKB,RTC