【从零到Offer】MySQL最左匹配

前言

​ 相信大家在日常开发时,也经常能听到“最左匹配”这个词,那么什么是最左匹配呢?本篇文章就带你一起探索“最左匹配”的神奇秘密。

什么是最左匹配

​ 最左匹配,通常指的是最左前缀匹配原则,即MySQL在检索数据时从联合索引的最左边开始匹配。

​ 那么如何检验MySQL确实是按照最左匹配在查询数据呢?实践是检验真理的唯一标准。

create table index_table
(
    id           int auto_increment,
    a 		int			default 0 not null 	,
    b       int         default 0 not null ,
    c       int         default 0 not null ,
    d		int			default 0 not null,
    constraint index_table_id_uindex
        unique (id)
);

create index index_table_a_b_c_index
    on index_table (a, b, c);

​ 这里新建一张数据表,并建立(a,b,c)三列的联合索引。建好表后,往表中添入数据。

image-20240211140947861

​ 如此一来初始数据就准备好了。但是下一个问题来了,如何检验当前查询是否走了对应的索引呢?这里简单介绍下MySQL是如何执行SQL的:

image-20240210160609881

​ MySQL执行一句SQL主要经过以下几个步骤:

1、客户端同连接池建立通信协议链接。

2、MySQL将传入的SQL放入到查询缓存中执行。

3、若非查询SQL或缓存未命中,则请求解析器进行语法解析并生成语法树。

4、对生成的解析树,MySQL的优化器会再次按照最优路径等方法进行优化。

5、利用优化后的解析树生成执行计划。

6、存储引擎执行相应的执行计划,将查询结果或修改结果返回给用户,至此SQL执行流程结束。

​ 可以看到在第5步,如果能拿到这句SQL的执行计划,那么SQL的执行效率、使用的索引情况就明了了。那么如何获取到SQL的执行计划呢?很简单,在MySQL中,有一个十分重要的关键字"Explain"。这里简单通过一个例子来说明:

	explain select * from index_table where a = 1 and b = 20 and c = 0;
	explain select * from index_table where b = 20 and c = 0;

​ 这里,采用explain关键字对SQL进行分析。可以看到执行完后,结果如下。

image-20240211140659921

image-20240213203258322

​ 上述列所表达的意思简单解释如下:

img

​ 通过"Explain"关键字,可以看到MySQL在执行第一句SQL时是走了索引的,但是第二句SQL是没有走索引的。那么到此,可以知道,MySQL确实是按最左匹配的方式在查询数据的。

最左匹配原理

​ 那么到这里,又有了新的疑问。为什么MySQL选择的是最左匹配的方式呢?这就还得从MySQL自身的索引结构说起。

​ 众所周知,索引的结构种类其实是有很多的,如:哈希索引、二叉树索引、B+树索引等等。MySQL基于检索效率等方面考虑,选择B+树作为自身的索引结构。

​ 这里以前面的数据为例,绘制出了MySQL建立的B+树索引:

image-20240211142822343

​ 简单来讲,在建立联合索引的时候,MySQL会优先按照索引的左边的第一个字段进行排序。对应到图中,也就是优先按照了列a进行排序。

​ 如果列a相同的情况下,MySQL则按联合索引的第二列b进行排序。聚焦到图中就是(3,3,1)和(3,5,0)这两个数据。它们的列a是相同的,但列b是从小到大排序的。

​ 了解了索引的建立方式,想必你也就明白了为什么是最左匹配了吧?索引本身的顺序是从左到右建立的,因此在搜索的时候,自然也是需要从左到右去匹配生效的。

​ 以刚才SQL为例,**“where a = 1 and b = 20 and c = 0;”**的部分,MySQL会优先选择用a=1搜索索引的位置(因为a已经是排好序的),倘如a=1的数据有多条。那么就会聚焦到b进行搜索,因为列b肯定也是按照顺序排列好的。因此只需要再按照b进行搜索即可。

注意事项

​ 那么聊到这里,可能有些读者就有疑惑了。“那我们以后搜索使用where条件语句的时候,都需要按照索引的方式搜索么?”

​ 答案显然是否定的。依旧以上文提到的(a,b,c)联合索引为例子,具体来说,可以分成如下几种特殊情况:

搜索SQL使用索引情况
情况一where a=? and c=? and b=?正常使用索引
情况二where a=? and c=?仅仅对a列使用了索引,c采用索引下推。
情况三where b=? and c=?无法使用索引

情况一

​ 按照情况一来看,可以看到where的条件并不是完全按照联合索引的顺序建立的,但是联合索引依旧生效了。可能很多人会有疑惑,不是说按照最左匹配才生效吗?回顾到前文中的SQL的执行流程,不难发现在生成SQL的执行计划之前,MySQL的解析器和优化器是会对传入的SQL语句进行解析、优化的。

image-20240211151540386

​ 在这个过程中,MySQL会自动调整where条件中的条件顺序,以便查询能够以最小的成本进行。所以并非是最左匹配的原则失效了,只是MySQL已经自动帮你处理好了这个转变过程,使得你在编程、查询的时候不需要再考虑索引顺序的问题。

情况二

​ 对情况二,a列可以正常采用索引,因为前面已经提到,联合索引是从左到右建立有效序列的,因此a列肯定是可以有序搜索的。但后续并没有b列,因此联合索引就没法再使用了。那么这个时候,MySQL如何进行c列的搜索呢?

​ 这里就不得不提及一个MySQL针对这种情况的优化,这种优化被称为索引下推。这里简单用例子:"select * from index_table where a>0 and c=1*"来解释一下。

image-20240211153021999

​ 正常来说,在where条件语句中,a>0是可以采用索引的,此时根据这个条件能够获取出一大批数据。根据索引中的这批数据,MySQL会按找id进行回表查询,查询完成后再根据where的其他条件进行筛选。

​ 但是,这种方法会带来很多的不必要回表,以图中为例,在联合索引中,其实保存了c列的数据,只需要根据c列再进行一次判断,就可以筛选出需要回表的数据只有一条,从而就可以大大减少回表的次数,达到优化查询的目的。

image-20240211155942890

​ 因此,MySQL为了减少回表查询的次数,就针对这种联合索引匹配不上的情况做了优化,就是在已经用联合索引筛选出数据的情况下,再次使用联合索引中的叶子结点数据,来判断where语句中的其余条件是否可以符合。若不符合,则不再对该数据做回表,从而加快数据查询的效率。

情况三

​ 对于情况三,那么由于它没有以a列作为查询的条件,相当于最左侧的列都无法匹配上。那么此时无论MySQL如何处理,都是没法调整顺序使其符合联合索引的,因此只能按照全表搜索的方式,而这也是最慢的搜索情况。

总结

​ 综合这以上三种情况,可以看到,MySQL在查询的时候,会优先用联合索引中最左侧的列进行匹配,并且会想方设法让用户的SQL能够符合联合索引。

​ 这也提示我们,在建立联合索引的时候,联合索引的列查询频率应该是从左到右递减的,由此一来,联合索引才能发挥最大的功效,也尽可能避免出现索引失效的情况。

参考资料

腾讯面试官问我:MySQL索引原理是什么?

MySQL索引,最左前缀匹配的内部原理是什么?

这篇 MySQL 索引和 B+Tree 讲得太通俗易懂

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c++ Qt 数据库操作

1、准备工作 Qt本身并没有数据库功能,但是Qt支持调用其他主流的数据库产品,并且这些数据库产品统一了Qt的接口,实际上是一种数据库的中间件。 Qt支持以下数据库类型: 嵌入式常用的数据库是sqlite3,本体只有几兆大小。非…

UnityShader玉石效果

效果: 代码: Shader "MyShader/Jade" {Properties{_DiffuseColor("漫反射颜色",color)(1,1,1,1)_ThicknessMap("厚度图",2d)"white"{}_AddColor("叠加颜色",color)(1,1,1,1)_CubeMap("环境贴图…

java实现多级目录树(递归实现)

一.应用场景 有时候需要我们后台给前台传树结构的数据,要怎么查询? 怎么返回数据呢? 二.数据库表设计以及数据内容(以部门举例) id 主键 parent_id 父级部门id depart_name 部门名词 sort 部门排序三.实体类 Data public…

Qt 软件封装与打包

1. Qt 软件封装 1、首先以 release 方式进行编译,将生成的 CloudOne.exe 文件复制到 D:\CloudApp 文件夹(自行创建) 2、打开 Qt 命令行工具(如下图所示),并按顺序输入如下指令 cd D:\CloudApp windeployq…

Spring Boot 笔记 019 创建接口_文件上传

1.1 创建阿里OSS bucket OSS Java SDK 兼容性和示例代码_对象存储(OSS)-阿里云帮助中心 (aliyun.com) 1.2 编写工具类 package com.geji.utils;import com.aliyun.oss.ClientException; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun…

每日一题——数字翻转

题目; 这道题看似是很简单的回文数 实则就是很简单的回文数 但是需要注意的一点是负数 可以在开头就进行判断&#xff0c;如果N<0的话就令N-N&#xff0c;将所有数都转成正数就好办了 上代码&#xff1a; #include <iostream> #include<string> #include<…

算法沉淀——哈希算法(leetcode真题剖析)

算法沉淀——哈希算法 01.两数之和02.判定是否互为字符重排03.存在重复元素04.存在重复元素 II05.字母异位词分组 哈希算法&#xff08;Hash Algorithm&#xff09;是一种将任意长度的输入&#xff08;也称为消息&#xff09;映射为固定长度的输出的算法。这个输出通常称为哈希…

Spring Security学习(四)——登陆认证(包括自定义登录页)

前言 和前面的文章隔了很长时间才更新Spring Security系列&#xff0c;主要原因一个是之前太忙了&#xff0c;把项目都忙完了&#xff0c;赶上春节假期&#xff0c;就慢慢研究。Spring Security的体系非常复杂&#xff0c;一口吃不了热豆腐&#xff0c;没办法速成&#xff0c;…

微服务—ES数据同步

目录 数据同步 问题分析 方案1. 同步调用 方案2. 异步通知 方案3. 监听binlog​编辑 各方案对比 案例——利用MQ实现数据同步 步骤1. 导入hotel-admin项目 步骤2. 声明交换机、队列 步骤3. 发送MQ消息 步骤4. 接收MQ消息 步骤5. 测试同步功能 数据同步 elasticsea…

八、键盘响应

之前博文格式已经固定&#xff0c;这里就不在赘述了&#xff0c;直接把核心代码进行解释一下即可&#xff0c;仅作为小笔记而已 项目实现功能&#xff1a; 按下键盘0&#xff0c;显示原始图像 按下键盘1&#xff0c;显示原始图像的灰度图 按下键盘2&#xff0c;显示原始图像的…

Python-To-Do-List

今天跟着油管学习创建了简单的代办事项列表应用程序&#xff0c;使用了python的tkinter库来制作图形用户界面&#xff08;GUI&#xff09; 1. 导入tkinter库 python Copy code import tkinter from tkinter import * 这两行导入了tkinter模块&#xff0c;它是Python的标准GUI库…

六、Redis之数据持久化及高频面试题

6.1 数据持久化 官网文档地址&#xff1a;https://redis.io/docs/manual/persistence/ Redis提供了主要提供了 2 种不同形式的持久化方式&#xff1a; RDB&#xff08;Redis数据库&#xff09;&#xff1a;RDB 持久性以指定的时间间隔执行数据集的时间点快照。AOF&#xff0…

django CBV 与 DRF APIView源码分析

django CBV源码分析 在django框架中&#xff0c;视图层中的逻辑即可以使用函数处理也可以使用类进行处理&#xff0c;如果在视图层中使用函数处理请求&#xff0c;就是FBV(function base views)&#xff0c;如果在视图层中使用类处理请求&#xff0c;就是CBV(class base views…

微信,支付宝在线换钱平台系统源码

探索全新、全开源的在线换钱系统源码&#xff0c;它将以前所未有的方式改变您的支付体验。我们为您精心打造了一个集简单易用与安全高效于一身的优质产品&#xff0c;它采用最新的技术开发&#xff0c;为您带来前所未有的便捷与安心。 这款在线换钱系统源码设计直观&#xff0…

【大数据Hive】hive 表设计常用优化策略

目录 一、前言 二、hive 普通表查询原理 2.1 操作演示说明 2.1.1 创建一张表&#xff0c;并加载数据 2.1.2 统计3月24号的登录人数 2.1.3 查询原理过程总结 2.2 普通表结构带来的问题 三、hive分区表设计 3.1 区表结构 - 分区设计思想 3.2 操作演示 3.2.1 创建分区表…

每日一题(数字颠倒,单词倒排)

数字颠倒_牛客题霸_牛客网 (nowcoder.com) #include <stdio.h>int main() {char arr[100];gets(arr);int lenstrlen(arr);for(int ilen-1;i>0;i--){printf("%c",arr[i]);}return 0; } 单词倒排_牛客题霸_牛客网 (nowcoder.com) #include <stdio.h> #…

《Java 简易速速上手小册》第4章:Java 中的异常处理(2024 最新版)

文章目录 4.1 异常类型和错误 - 遇见你的小怪兽4.1.1 基础知识4.1.2 重点案例&#xff1a;文件读取处理4.1.3 拓展案例 1&#xff1a;处理空指针异常4.1.4 拓展案例 2&#xff1a;捕获多个异常 4.2 异常处理机制 - 穿上你的超级英雄斗篷4.2.1 基础知识4.2.2 重点案例&#xff1…

Vuex 模块的详解

Vuex 模块是将 store 分割成多个模块的一种方式&#xff0c;每个模块都有自己的状态、mutations、actions 和 getters。这有助于更好地组织和管理应用程序的状态。 创建模块&#xff1a; 首先&#xff0c;需要创建一个模块。可以在 store 中定义一个新的模块对象&#xff0c…

python小项目----多重剪切板

代码&#xff1a; import shelve,pyperclip,sysimport mcbmcbShelfshelve.open(mcb)# 保存剪切板内容 if len(sys.argv)3 and sys.argv[1].lower()save:#剪切板的内容保存到第三个参数中mcbShelf[sys.argv[2]]pyperclip.paste()print("你的剪切板中的内容将被保存到mcbSh…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 2月14日,星期三

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年2月14日 星期三 农历正月初五 1、 第十四届全国冬季运动会将于17日开幕&#xff0c;部分赛事今天起陆续开赛。 2、 2024年购房政策将进一步宽松&#xff0c;专家称今年买房性价比更高。 3、 春节档票房突破45亿元&#…