如何优化mysql索引-最左前缀原则案例详解

也许大多数人对索引优化的理解就是调优SQL。一般来说,是看它是否有索引,如果没有就给它添加索引。但不是这样的。#如何优化mysql索引#

如果想做好索引优化,就需要了解它的底层逻辑。

最左前缀原则

我们一般要优化复杂的SQL,而复杂的SQL一般会使用联合索引。说到联合索引的匹配规则,我们就逃不开这个:最左前缀规则。

简单解释一下,最左边前缀规则就是:索引的匹配从最左边的字段开始,只有匹配成功才能继续匹配到右边的下一个字段。

我们先来看看这个联合索引idx_nme_age_school。

假设我们现在有一张student表

r 复制代码
CREATE TABLE `students` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) NOT NULL,
  `age` int NOT NULL,
  `school` varchar(255) NOT NULL,
  `address` varchar(255) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name_age_school` (`name`,`age`,`school`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3

idx_name_age_school的联合索引由name、age、school三个字段组织,字段顺序相同。

首先,我们都知道索引实际上是一种高效的数据结构。

那么对于索引idx_name_age_school,就会这样排序。

  • 名称字段从小到大排序。

  • 当name字段的值相同时,age字段从小到大排序。

  • 当age字段的值相同时,school字段从小到大排序。

如上图所示,顺序是从n_18到n_100,而名字为n_18的三个节点中,年龄从小到大排序,年龄相同时,学校也从小到大排序。

用这个联合索引来分析最左边前缀的规则:索引匹配时,必须先匹配name字段(最左边),然后才能匹配age字段(下一个)。只有年龄字段匹配成功,才能匹配学校字段。

这是因为联合索引中最左边的字段是有序的,所以当第一个字段相同时,第二个字段有序,当第二个字段相同时,第三个字段有序。

如果想用age字段直接查找数据是找不到的,因为age字段在联合索引中是无序的。

还是有点困惑?没关系,我们再分析以下案例。

如何命中索引

就是看索引会不会发挥作用,如果能发挥作用,那就是命中索引。

SQL1

sql 复制代码
EXPLAIN SELECT * FROM students WHERE NAME > 'n_18';

name字段是联合索引最左边的字段,所以会命中索引。

SQL2

ini 复制代码
EXPLAIN SELECT * FROM students WHERE age = 18;

Age字段不是联合索引的最左边字段,而且在索引中是乱序的,所以不使用索引,需要全表扫描

SQL3

ini 复制代码
EXPLAIN SELECT * FROM students WHERE NAME = 'n_18' AND age = 20;

name字段和age字段都会命中索引,因为当name字段相同时,age字段是有序的,所以age此时也能命中索引。

以上图为例。当定位到n_18时,可以直接定位到age=20的数据,不需要从age=18开始查找,所以索引在age字段中也发挥了作用。

深入分析

SQL4

ini 复制代码
EXPLAIN SELECT * FROM students WHERE age = 20 AND NAME = 'n_18';

和SQL3一样,name和age都会用到索引,最左边的前缀和你sql语句的位置无关,MySQL在执行过程中会自动调整位置,数据库优化器会自动将语句改为name = "n_18 " and age = 20 。

SQL5

csharp 复制代码
explain select * from students where name > 'n_18' and age = 20;

只有name字段用到索引,age不会用到索引。 因为此时mysql的查询逻辑是定位到name=n_18最右边的一条数据,然后通过叶子节点的指针向右扫描遍历,所以索引对age字段没有影响。

SQL6

csharp 复制代码
explain select * from students where name >= 'n_18' and age = 20;

与SQL5类似,唯一的区别是name大于或等于。 此时,name和age都会被索引。

现在,我猜你一定有点困惑,正常情况下范围查找不会导致索引失败吗?

那么为什么age字段还能用到索引? 我们可以把这个SQL改成一种写法。

csharp 复制代码
explain select * from students where (name = 'n_18' and age = 20) or (name > 'n_18' and age = 20);

对于查询条件name = 'n_18'和age = 20,name和age都能用到索引。

对于查询条件name > 'n_18'和age = 20,只有name用到索引。

当两个查询条件组合时,两个字段都会被索引。

SQL7

sql 复制代码
explain select * from students where name like 'n_18%' and age = 10;

与 SQL6 相同,姓名和年龄都会用到索引。 但要注意,这条SQL在MySQL8下执行时不会走索引。

SQL8

sql 复制代码
explain select * from students where name between 'n_18' and 'n_50' and age = 10;

与 SQL7 相同,name和age都将被索引。 但要注意,这条SQL在MySQL8下执行时不会走索引。

至此,你应该对最左前缀规则有了深入的了解,更多的思路可以自己探索。

如果喜欢本内容的话,关注公众号查看更多内容,微信搜索:京城小人物,或者扫描下方二维码,动动小手给作者一个鼓励,比心!

相关推荐
smartvxworks2 分钟前
Linux 实时内核(Linux Real-Time Kernel)详解:原理、实践与优化
java·linux·服务器
qizayaoshuap3 分钟前
# [特殊字符] 密码生成器 — 鸿蒙ArkTS安全算法与密码强度评估系统
java·算法·安全·华为·harmonyos
AC赳赳老秦5 分钟前
OpenClaw 采集任务日志审计:全程记录采集行为,满足合规溯源与企业审计要求
java·大数据·python·数据挖掘·数据分析·php·openclaw
2501_9185823716 分钟前
HarmonyOS应用开发实战:小事记 - Stage 模型下 EntryAbility 的启动流程与 Want 解析机制
后端
IT瑞先生35 分钟前
Docker快速部署Mysql的三种方法——实操篇
mysql·adb·docker
风起洛阳@不良使38 分钟前
spring中xml和注解开发的对比
xml·java·spring
Tenifs42 分钟前
关闭 IDEA 的英文单词拼写检查
java·intellij-idea
captain3761 小时前
创建多线程程序
java·java-ee
野蛮人6号1 小时前
黑马天机学堂Day01-08.搭建项目环境-本地开发部署方式——不知道nacos的密码是什么
java·spring cloud·黑马程序员·天机学堂·黑马天机学堂
Roy_Sashulin1 小时前
灵杉Java编程平台第一章:安装
java·开发语言