【联合索引】最左匹配原则是什么?

news2024/11/25 22:25:43

什么是联合索引

联合索引(Composite Index)是一种索引类型,它由多个列组成。
MySQL的联合索引(也称为复合索引)是建立在多个字段上的索引。这种索引类型允许数据库在查询时同时考虑多个列的值,从而提高查询效率和性能。
联合索引:也称复合索引,就是建立在多个字段上的索引。联合索引的数据结构依然是 B+ Tree

例如:当使用(col1, col2, col3)创建一个联合索引时,创建的只是一颗B+ Tree,在这棵树中,会先按照最左的字段col1排序,在col1相同时再按照col2排序,col2相同时再按照col3排序。

联合索引的存储结构

联合索引是一种特殊类型的索引,它包含两个或更多列

在MySQL中,联合索引的数据结构通常是B+Tree,这与单列索引使用的数据结构相同。
当创建联合索引时,需要注意列的顺序,因为这将影响到索引的使用方式。
如下图所示,表的数据如右图,ID 为主键,创建的联合索引为 (a,b),注意联合索引顺序,下图是模拟的联合索引的 B+ Tree 存储结构
在这里插入图片描述

最左匹配原则

联合索引还是一颗B+树,只不过联合索引的健 数量不是一个,而是多个。
构建一颗B+树只能根据一个值来构建,因此数据库依据联合索引最左的字段来构建B+树。
假如创建一个(a,b)的联合索引,联合索引B+ Tree结构如下:
在这里插入图片描述
结合上述联合索引B+ Tree结构,可以得出如下结论:
1.a的值是有顺序的,1,1,2,2,3,3,而b的值是没有顺序的1,2,1,4,1,2。
所以b = 2这种查询条件没有办法利用索引,因为联合索引首先是按a排序的,b是无序的。
2.当a值相等的情况下,b值又是按顺序排列的,但是这种顺序是相对的。
所以最左匹配原则遇上范围查询就会停止,剩下的字段都无法使用索引。
例如a = 1 and b = 2 ,a,b字段都可以使用索引,因为在a值确定的情况下b是相对有序的,而a>1and b=2,a字段可以匹配上索引,但b值不可以,因为a的值是一个范围,在这个范围中b是无序的。

最左匹配原则
最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。
下面我们以建立联合索引(a,b,c)为例,进行详细说明

1、全值匹配查询时

下述SQL会用到索引,因为where子句中,几个搜索条件顺序调换不影响查询结果,因为MySQL中有查询优化器,会自动优化查询顺序。

select * from table_name where a = '1' and b = '2' and c = '3' 
select * from table_name where b = '2' and a = '1' and c = '3' 
select * from table_name where c = '3' and b = '2' and a = '1'

2、匹配列前缀

如果a是字符类型,那么前缀匹配用的是索引,后缀和中缀只能全表扫描了

select * from table_name where  a like 'As%';   //前缀都是排好序的,走索引查询
select * from table_name where  a like '%As';   //全表查询
select * from table_name where  a like '%As%';  //全表查询

3、匹配左边的列时

下述SQL,都从最左边开始连续匹配,用到了索引。

select * from table_name where a = '1' 
select * from table_name where a = '1' and b = '2'  
select * from table_name where a = '1' and b = '2' and c = '3'

下述SQL中,没有从最左边开始,最后查询没有用到索引,用的是全表扫描。

select * from table_name where  b = '2' 
select * from table_name where  c = '3'
select * from table_name where  b = '1' and c = '3' 

下述SQL中,如果不连续时,只用到了a列的索引,b列和c列都没有用到

select * from table_name where  a = '1' and c = '3' 

4、匹配范围值

下述SQL,可以对最左边的列进行范围查询

select * from table_name where  a > 1 and a < 3

多个列同时进行范围查找时,只有对索引最左边的那个列进行范围查找才用到B+树索引,也就是只有a用到索引。
在1<a<3的范围内b是无序的,不能用索引,找到1<a<3的记录后,只能根据条件 b > 1继续逐条过滤。

select * from table_name where  a > 1 and a < 3 and b > 1;

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

如果左边的列是精确查找的,右边的列可以进行范围查找,如下SQL中,a=1的情况下b是有序的,进行范围查找走的是联合索引

select * from table_name where  a = 1 and b > 3;

6、排序

一般情况下,我们只能把记录加载到内存中,再用一些排序算法,比如快速排序,归并排序等在内存中对这些记录进行排序,有时候查询的结果集太大不能在内存中进行排序的话,还可能暂时借助磁盘空间存放中间结果,排序操作完成后再把排好序的结果返回客户端。
Mysql中把这种再内存中或磁盘上进行排序的方式统称为文件排序。文件排序非常慢,但如果order子句用到了索引列,就有可能省去文件排序的步骤

select * from table_name order by a,b,c limit 10;

因为b+树索引本身就是按照上述规则排序的,所以可以直接从索引中提取数据,然后进行回表操作取出该索引中不包含的列就好了,order by的子句后面的顺序也必须按照索引列的顺序给出,比如下SQL,在以下SQL中颠倒顺序,没有用到索引

select * from table_name order by b,c,a limit 10;

以下SQL中会用到部分索引,联合索引左边列为常量,后边的列排序可以用到索引

select * from table_name where a =1 order by b,c limit 10;

跳跃扫描机制

一定要遵循最左匹配原则吗?

最左前缀匹配原则,也就是SQL的查询条件中必须要包含联合索引的第一个字段,这样才能命中联合索引查询,但实际上这条规则也并不是100%遵循的。
因为在MySQL8.x版本中加入了一个新的优化机制,也就是索引跳跃式扫描,这种机制使得咱们即使查询条件中,没有使用联合索引的第一个字段,也依旧可以使用联合索引,看起来就像跳过了联合索引中的第一个字段一样,这也是跳跃扫描的名称由来。
我们来看如下例子,理解一下索引跳跃式扫描如何实现的。
比如此时通过(A、B、C)三个列建立了一个联合索引,此时有如下一条SQL:

SELECT * FROM table_name WHERE B = `xxx` AND C = `xxx`;

按正常情况来看,这条SQL既不符合最左前缀原则,也不具备使用索引覆盖的条件,因此绝对是不会走联合索引查询的。
但这条SQL中都已经使用了联合索引中的两个字段,结果还不能使用索引,这似乎有点亏啊?
因此MySQL8.x推出了跳跃扫描机制,但跳跃扫描并不是真正的“跳过了”第一个字段,而是优化器为你重构了SQL,比如上述这条SQL则会重构成如下情况:

SELECT * FROM `table_name ` WHERE B = `xxx` AND C = `xxx`
UNION ALL
SELECT * FROM `table_name ` WHERE B = `xxx` AND C = `xxx` AND A = "yyy"
......
SELECT * FROM `table_name ` WHERE B = `xxx` AND C = `xxx` AND A = "zzz";

通过MySQL优化器处理后,虽然你没用第一个字段,但优化器给你加上去,今天这个联合索引你就得用,不用也得给我用。

但是跳跃扫描机制也有很多限制,比如多表联查时无法触发、SQL条件中有分组操作也无法触发、SQL中用了DISTINCT去重也无法触发等等,总之有很多限制条件,具体的可以参考《MySQL官网8.0-跳跃扫描》。

可以通过通过如下命令来选择开启或关闭跳跃式扫描机制。

set @@optimizer_switch = ‘skip_scan=off|on’;

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

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

相关文章

物联网五层架构分析

物联网五层架构分析 随着科技的迅速发展&#xff0c;物联网&#xff08;IoT&#xff09;作为日常生活中不可或缺的一部分&#xff0c;已融入人们的生活和工作中。物联网五层架构&#xff0c;包括感知层、网络层、数据层、应用层和业务层&#xff0c;扮演着关键的角色。 感知层 …

通往糊涂之路 The road to serfdom

最近被推送了一本书&#xff0c;哈耶克的............ 试一试&#xff0c;看看能不能看懂&#xff0c;也许是通往糊涂之路。

IMDB的电影评论数据pytorh使用lstm

使用lstm对IMDB的电影评论数据进行情感分析&#xff08;pytorch代码&#xff09; 接下来让我们看看如何使用pytorch实现一个基于长短时记忆网络的情感分析模型。在飞桨中&#xff0c;不同深度学习模型的训练过程基本一致&#xff0c;流程如下&#xff1a; 数据处理&#xff1…

鸿蒙开发接口Ability框架:【AbilityMonitor】

AbilityMonitor AbilityMonitor模块提供匹配满足指定条件的受监视能力对象的方法的能力&#xff0c;最近匹配的能力对象将保存在AbilityMonitor对象中。 说明&#xff1a; 本模块首批接口从API version 9 开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起…

C#之partial关键字

在C#中&#xff0c;partial关键字用于声明一个类、结构体、接口或方法的分部定义。这意味着可以将一个类或其他类型的定义分成多个部分&#xff0c;这些部分可以在同一个命名空间或程序集中的多个源文件中进行定义。当编译器编译这些部分时&#xff0c;会将它们合并成一个单独的…

LeetCode/NowCoder-链表经典算法OJ练习2

最好的&#xff0c;不一定是最合适的&#xff1b;最合适的&#xff0c;才是真正最好的。&#x1f493;&#x1f493;&#x1f493; 目录 说在前面 题目一&#xff1a;分割链表 题目二&#xff1a;环形链表的约瑟夫问题 SUMUP结尾 说在前面 dear朋友们大家好&#xff01;&…

【计算机网络】Socket网络编程

&#x1f4bb;文章目录 &#x1f4c4;前言Socket编程基础概念工作原理 Socket API介绍socket函数绑定、监听函数accept、connect接受/发送函数 Socket API的应用Socket类与其派生类的设计服务器与客户端的设计使用 &#x1f4d3;总结 &#x1f4c4;前言 现今我们的日常生活当中…

【爬虫基础1.1课】——requests模块上

目录索引 requests模块的作用&#xff1a;实例引入&#xff1a; 特殊情况&#xff1a;锦囊1&#xff1a;锦囊2: 这一个栏目&#xff0c;我会给出我从零开始学习爬虫的全过程。感兴趣的小伙伴可以关注一波&#xff0c;用于复习和新学都是不错的选择。 那么废话不多说&#xff0c…

sqli-labs 第十七关

目录 找注入点&#xff1a; 源码分析&#xff1a; 测试&#xff1a; 奇怪现象&#xff1a; &#xff08;1&#xff09;&#xff1a;当我们输入的密码为字符进行注入时。 &#xff08;2&#xff09;&#xff1a;当我们输入的密码为整数时。 产生原因&#xff1a; 解决方法…

孙宇晨对话大公网:香港Web3政策友好环境示范意义重大

日前,全球知名华文媒体大公网发布《湾区web3大有可为》重磅系列报道。报道通过对中国香港与大湾区其他城市Web3政策、行业创新和生态建设等方面的梳理,以及对行业领袖和重要行业机构的走访,全面展现了在大湾区一体化发展的背景下,Web3等数字经济模式在该地区的长远发展潜力。 …

基于Idea搭建Android开发环境

文章目录 下载SDK ManagerAndroid SDK Platform-toolsAndroid SDK Build-toolsAndroid SDKAndroid SDK Extras IDEA设置创建TestApp导入Android Studio创建的项目 下载SDK Manager SDK Manager是Google提供的&#xff0c;专门用于下载/管理&#xff0c;安卓开发中需要用到的工…

【MYSQL】一颗B+树可以保存多少条数据

引言 事万物都有自己的单元体系&#xff0c;若干个小单体组成一个个大的个体。就像拼乐高一样&#xff0c;可以自由组合。所以说&#xff0c;如果能熟悉最小单元&#xff0c;就意味着我们抓住了事物的本事&#xff0c;再复杂的问题也会迎刃而解。 存储单元 存储器范围比较大…

鸿蒙ArkUI开发:常用布局【交叉轴】

交叉轴 垂直于主轴方向的轴线。Row容器交叉轴为纵向&#xff0c;Column容器交叉轴为横向。通过alignItems属性设置子元素在交叉轴&#xff08;排列方向的垂直方向&#xff09;上的对齐方式alignSelf属性用于控制单个子元素在容器交叉轴上的对齐方式&#xff0c;其优先级高于al…

鸿蒙内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)

本篇为快锁下篇&#xff0c;说清楚快锁在内核态的实现&#xff0c;解答以下问题&#xff0c;它们在上篇的末尾被提出来。 鸿蒙内核进程池默认上限是64个&#xff0c;除去两个内核进程外&#xff0c;剩下的都归属用户进程&#xff0c;理论上用户进程可以创建很多快锁&#xff0…

Wikimedia To Opensearch

概览 Wikimedia ⇒ Kafka ⇒ OpensearchJava Library&#xff1a;OKhttp3和OkHttp EventSource&#xff1b;生产者&#xff1a;Wikimedia&#xff1a;WikimediaChangeHandler和WikimediaChangeProducer&#xff1b;消费者&#xff1a;Opensearch&#xff1a;OpenSearchConsume…

【知识碎片】2024_05_13

本文记录了两道代码题【自除数】和【除自身以外数组的乘积】&#xff08;利用了前缀积和后缀积&#xff0c;值得再看&#xff09;&#xff0c;第二部分记录了关于指针数组和逗号表达式的两道选择题。 每日代码 自除数 . - 力扣&#xff08;LeetCode&#xff09; /*** Note: T…

k8s StatefulSet

Statefulset 一个 Statefulset 创建的每个pod都有一个从零开始的顺序索引&#xff0c;这个会体现在 pod 的名称和主机名上&#xff0c;同样还会体现在 pod 对应的固定存储上。这些 pod 的名称是可预知的&#xff0c;它是由 Statefulset 的名称加该实例的顺序索引值组成的。不同…

JUC下的ThreadLocalRandom详解

ThreadLocalRandom 是Java并发包&#xff08;java.util.concurrent&#xff09;中提供的一个随机数生成器类&#xff0c;它是从Java 7开始引入的。相较于传统的Math.random()或Random类&#xff0c;ThreadLocalRandom更适用于多线程环境&#xff0c;因为它为每个线程维护了一个…

汇昌联信电商:拼多多新手怎么做店铺的免费流量会慢慢起来?

在拼多多上开店&#xff0c;新手们往往面临着如何吸引免费流量的挑战。毕竟&#xff0c;流量是店铺生存和发展的血脉&#xff0c;没有流量&#xff0c;就没有销量&#xff0c;店铺也就失去了生命力。那么&#xff0c;作为拼多多新手&#xff0c;如何做才能让店铺的免费流量慢慢…

设计模式Java实现-迭代器模式

✨这里是第七人格的博客✨小七&#xff0c;欢迎您的到来~✨ &#x1f345;系列专栏&#xff1a;设计模式&#x1f345; ✈️本篇内容: 迭代器模式✈️ &#x1f371; 本篇收录完整代码地址&#xff1a;https://gitee.com/diqirenge/design-pattern &#x1f371; 楔子 很久…