最左前缀在mysql的官方文档中称之为leftmost prefix,该原则适用于多列索引,想仅仅用三言两语来说清楚什么是最左前缀匹配原则不太现实,但是如果使用官方文档的一个例子来说明该原则,或许会好得多。

假如现在有一张表的创建语句如下:

CREATE TABLE test (

id INT NOT NULL,

last_name CHAR(30) NOT NULL,

first_name CHAR(30) NOT NULL,

PRIMARY KEY (id),

INDEX name (last_name,first_name)

);

那么如下的sql可以命中name索引:

SELECT * FROM test WHERE last_name='Jones';

SELECT * FROM testWHERE last_name='Jones' AND first_name='John';

SELECT * FROM test WHERE last_name='Jones' AND (first_name='John' OR first_name='Jon');

SELECT * FROM test WHERE last_name='Jones' AND first_name >='M' AND first_name < 'N';

如下的sql无法命中name索引:

SELECT * FROM test WHERE first_name='John';

SELECT * FROM test WHERE last_name='Jones' OR first_name='John';

为什么前四个sql可以命中name索引,后两个sql却不行呢?因为name索引的定义是last_name在前,first_name在后,所以它的最左前缀有两个:last_name、last_name first_name(题外话:如果有一个索引的定义为idx(col1, col2, col3),那么它的最多前缀有哪些呢?答案是有三个:col1、col1 col2、col1 col2 col3),前4个sql的where条件都是以最左前缀的顺序依次作为查询条件,后2个sql却不是。

此时此刻,或许你还有很多疑问,比如为什么上面第3条or查询可以命中索引但是第6条就不行呢?范围查询呢?是不是我严格按照任意一个最左前缀书写sql,就一定会命中相应的索引?想要搞清楚这些问题,死记硬背一些原则或许是不合适的,还是应该尝试从本质上来探究这些问题。我们知道,在InnoDB存储引擎中,任何一个索引的数据结构都是B+树,该B+树如何构建取决于索引是如何定义的,以例子中的INDEX name (last_name,first_name)为例,肯定是以last_name为主要排序对象,如果last_name相同,则按照first_name排序,假如我们有如下数据行:

id=1, last_name=aaa, first_name=dwf;

id=2, last_name=zzz, first_name=ytr;

id=3, last_name=mmm, first_name=edf;

id=4, last_name=bbb, first_name=abc;

id=5, last_name=zzz, first_name=abc;

id=6, last_name=qqq, first_name=gfd;

id=7, last_name=aaa, first_name=rfg;

id=8, last_name=zzz, first_name=sdd;

id=9, last_name=hhh, first_name=bgf;

id=10, last_name=aaa, first_name=abc;

id=11, last_name=zzz, first_name=bfd;

id=12, last_name=lll, first_name=cba;

id=13, last_name=aaa, first_name=bvf;

id=14, last_name=zzz, first_name=abd;

id=15, last_name=lll, first_name=sdd;

id=16, last_name=mmm, first_name=nbv;

id=17, last_name=zzz, first_name=trd;

id=18, last_name=aaa, first_name=oiu;

假设一个数据块可以存放3行数据,那么它的B+树结构大概如下(索引页上面的三个字母代表last_name,下面的代表first_name):

下面来逐个分析上面6个sql。

1、SELECT * FROM test WHERE last_name='jones';

通过根索引页定位到第二层中间的索引页

通过第二层中间的索引页定位到第三层的第三个数据页(因为jones排序在lll的前面)

发现没有last_name='jones',返回null

因此可以命中索引。

2、SELECT * FROM testWHERE last_name='Jones' AND first_name='John';

通过根索引页定位到第二层中间的索引页

通过第二层中间的索引页定位到第三层的第三个数据页(因为jones排序在lll的前面)

发现没有last_name='jones'和first_name='John';,返回null

因此可以命中索引。

3、SELECT * FROM test WHERE last_name='Jones' AND (first_name='John' OR first_name='Jon');

该sql语句可以改写成,SELECT * FROM test WHERE last_name='Jones' AND first_name='John' OR(last_name='Jones' and first_name='Jon'),本质上和第2条sql一样,所以也可以命中索引。

4、SELECT * FROM test WHERE last_name='Jones' AND first_name >='M' AND first_name < 'N';

无非就是根据last_name一步步通过根索引页定位到相关的数据页,再通过数据页的页目录找到first_name是这个范围的,因为last_name相同的情况下,first_name是按顺序存储在数据页中的,所以也可以命中索引。

5、SELECT * FROM test WHERE first_name='John';

因为B+树是先按照last_name再按照first_name的顺序构建的,如果上去就按照first_name去查找相应的数据页,结果显然是不准确的。根索引页的first_name:dwf、gfd、ytr看起来确实是有顺序的,但实际上这完全是一个巧合,其实从第二层的第一个索引页的first_name也可以看出来:dwf、abc显然是无序的。只有当last_name一样时,first_name才是有顺序的,可以看看第三层第五个和第六个数据页,last_name都是zzz,first_name是按照顺序排列的,这也是为什么第4个sql可以命中索引的原因。

6、SELECT * FROM test WHERE last_name='Jones' OR first_name='John';

其实看这个sql的前半部分SELECT * FROM test WHERE last_name='Jones'其实可以通过该索引轻易地找到last_name='Jones'对应的数据页,但是下一步如何定位first_name='John'的数据页呢?显然等值查找first_name是无法使用该索引的,那就只能遍历聚簇索引的数据页,既然都遍历聚簇索引的数据页了,那为什么还要使用该索引定位last_name='Jones'的数据页呢,直接在遍历的时候顺带判断一下last_name的值不就好了吗,反正整个数据页都会加载到buffer_pool,无非就是在内存中做一次比较,所以不会命中该索引。

最后的话:以上仅仅是自己对于mysql理解,难免会有很多错误,望批评指正。

mysql最左前缀概念_Mysql的最左前缀匹配原则(上)相关推荐

  1. mysql自动提交的概念_MySQL入门之事务概念

    MYSQL默认是自动提交的,也就是你提交一个QUERY,它就直接执行!我们可以通过 set autocommit=0 禁止自动提交 set autocommit=1开启自动提交 mysql中INNOD ...

  2. mysql怎么建组合索引_mysql索引及建立组合索引原则

    两个重要概念 1.对于mysql来说,一条sql中,一个表无论其蕴含的索引有多少,但是有且只用一条. 2.对于多列索引来说(a,b,c)其相当于3个索引(a),(a,b),(a,b,c)3个索引,又由 ...

  3. mysql最左前缀概念_mysql查询优化之目录类型、最左前缀

    一.什么是索引?索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录.表里 ...

  4. mysql中视图的概念_MySql中的视图的概念及应用

    视图的基本概念 视图是从一个或几个基本表(或者视图)导出的表.它与基本表不同,是一个虚表. 数据库只存放视图的定义,而不存放视图对应的数据,这些数据仍存放在原来的基本表中.所以基本表中的数据发生变化, ...

  5. mysql左键关联_MySQL的:左键删除重复列加入,3个表

    我有一个表,使用3个外键到其他表.当我执行左连接时,我会收到重复的列. MySQL表示,USING语法将减少重复的列,但没有多个键的示例. 鉴于: mysql> describe recipes ...

  6. mysql可重复读概念_Mysql可重复读原理

    概念 可重复读的实现 Repeatable Read(可重复读):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录(读已经提交的,其实是读早于本事务开始且已经提交的),但是不能看到其他事务对 ...

  7. mysql批量修改学号位数_mysql批量修改表前缀

    如何快速批量修改文件名我们有时候在网页上,下载了好多自己喜欢的图片,一个个修改太麻烦了,想要快速 批量的修改文件名,其实,在你的 Windows 电脑上批量修改文件名...... 如何在 WPS 表格 ...

  8. mysql 表锁的概念_MySQL 锁的一些简单概念

    1. 锁的粒度 在MySQL中,只要有多个请求需要在同一时刻修改数据,都会产生并发控制的问题.而锁的作用可以保证同一资源能被某个请求唯一使用. 加锁是会消耗系统资源的,包括获得锁.检查锁是否已解除.释 ...

  9. mysql挪到小数点位置_mysql数据库迁移到另一个硬盘上

    archliun系统mysql数据库 1.对新硬盘分区与格式化 1)# fdisk /dev/sdb 2) # mkfs.ext4 /dev/sdb1 2.停止MYSQL服务 systemctl st ...

最新文章

  1. conda环境下如何升级python?
  2. 牛客 21302 被3整除的子序列 (动态规划、Python)
  3. linux nmap下载教程,Linux_在Linux系统上用nmap扫描SSL漏洞的方法,以下载nmap 6.45及以上版本。如 - phpStudy...
  4. 今日起开始预约!北京将发放5万份数字人民币红包
  5. java中写sql语句的小小细节
  6. 关于解决keil4和mdk共存后51不能使用go to definition Of 'XXXXXX'问题
  7. Mac cmake命令不可用-bash: cmake: command not found
  8. JDK动态代理入门、JDK动态代理原理、为什么JDK动态代理是基于接口的
  9. 清单软件217天使用总结
  10. java 斗地主出牌算法_斗地主智能(AI)出牌算法
  11. 4-渔夫打鱼晒网问题
  12. 关于JAVAFX的鼠标单击事件案例
  13. 关于SAP的用户出口
  14. python api文档生成二维码_使用Python第三方库生成二维码
  15. 【JavaScript】- 打地鼠游戏(定时器嵌套延时器)
  16. h5 vr效果_H5案例|通过VR展示的那些烧脑游戏
  17. vscode中添加好看字体的方法
  18. JMockit 介绍 4 使用JMockit运行测试
  19. Visio画UML类图
  20. 中学计算机课程课时,高中信息技术教案word操作(共5份8课时

热门文章

  1. 交易猫源码搭建完整版
  2. 大数据进阶之路——Spark SQL 之 DataFrameDataset
  3. 预览pdf时,中文乱码
  4. dll和lib的区别
  5. Windows Embedded Compact 7可定制化互联网电视
  6. 向内看 —— Stay hungry.Stay foolish
  7. 青云QingCloud 在不同场景化中的云计算应用
  8. [倚天屠龙记] vim 查找与替换(正则表达式)
  9. laravel下视图间共享数据
  10. 计算机专业进中国移动难吗,【计算机】中国移动面试技巧和注意事项