MySql最左匹配原则解析

看前提问:table中有多个字段组成的联合索引(a,b,c),查询时哪些情况能够命中索引呢?

 

话不多说,直接开搞:

数据库表结构如下:

CREATE TABLE `test` ( 
  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', 
  `class_id` int(4) NOT NULL DEFAULT '0' COMMENT '班级ID', 
  `score` int(4) NOT NULL DEFAULT '0' COMMENT '学分', 
  `total` int(4) NOT NULL DEFAULT '0' COMMENT '总计', 
  PRIMARY KEY (`id`), 
  KEY `idx_class_score_total` (`class_id`,`score`,`total`) COMMENT '测试表' 
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='测试表'; 

可以看到:表中根据class,score,total字段建立联合索引 idx_class_score_total ,下面开始验证我们的猜想;

 

首先我们验证当根据一个字段查询数据的情况:

 

上述结果发现:type有两种类型:ref和index;

index:这种类型表示mysql会对整个该索引进行扫描。要想用到这种类型的索引,对这个索引并无特别要求,只要是索引,或者某个联合索引的一部分,mysql都可能会采用index类型的方式扫描。但是呢,缺点是效率不高,mysql会从索引中的第一个数据一个个的查找到最后一个数据,直到找到符合判断条件的某个索引。所以,上述语句会触发索引。

ref:这种类型表示mysql会根据特定的算法快速查找到某个符合条件的索引,而不是会对索引中每一个数据都进行一一的扫描判断,也就是所谓你平常理解的使用索引查询会更快的取出数据。而要想实现这种查找,索引却是有要求的,要实现这种能快速查找的算法,索引就要满足特定的数据结构。简单说,也就是索引字段的数据必须是有序的,才能实现这种类型的查找,才能利用到索引。 

结果:根据一个字段查询的时候实际上都可以命中索引,只不过ref效率更高,index情况效率不高;

 

其次我们再来验证根据任意两个字段查询的结果:

 

上述实践可得:a_b,a_c可以命中索引,b_c没有命中索引;

是不是有个问题?为什么a_c也可以命中索引?

我们仔细观察下sql1和sql2的执行结果,可以发现key_len是不一样的且ref不一样,a_c命中索引并不是全命中,只是部分命中索引,命中的是a的索引,所以key_len=4且ref=const;

 

最后我们看下根据三个字段一起查询的结果(包括打乱顺序);

 

上述结果发现:两条sql的执行结果是一致的,所以当根据这三个字段查询数据时都可以命中索引无论顺序;

是不是又有一个疑问?为什么打乱顺序也可以命中索引?

mysql中的查询优化器会纠正这条sql语句该以哪种顺序执行效率最高,最后生成真正的执行计划(QEP),尽量利用到索引时查询顺序效率最高。所以mysql查询优化器最终会以(a_b_c)这种顺序查询,所以b_a_c可以命中索引;

 

附录:

各属性含义:

  • id: 查询的序列号

  • select_type: 查询的类型,主要是区别普通查询和联合查询、子查询之类的复杂查询

    • SIMPLE:查询中不包含子查询或者UNION
    • 查询中若包含任何复杂的子部分,最外层查询则被标记为:PRIMARY
    • 在SELECT或WHERE列表中包含了子查询,该子查询被标记为:SUBQUERY
  • table: 输出的行所引用的表

  • type: 访问类型

    • ALL: 扫描全表
    • index: 扫描全部索引树
    • range: 扫描部分索引,索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行,常见于between、<、>等的查询
    • ref: 使用非唯一索引或非唯一索引前缀进行的查找
    • (eq_ref和const的区别:)
    • eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
    • const, system: 单表中最多有一个匹配行,查询起来非常迅速,例如根据主键或唯一索引查询。system是const类型的特例,当查询- 的表只有一行的情况下, 使用system。
    • NULL: 不用访问表或者索引,直接就能得到结果,如select 1 from test where 1
  • key: 显示MySQL实际决定使用的索引。如果没有索引被选择,是NULL

  • key_len: 使用到索引字段的长度
    注:key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。

  • ref: 显示哪个字段或常数与key一起被使用

  • rows: 这个数表示mysql要遍历多少数据才能找到,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数,在innodb上可能是不准确的

  • Extra: 执行情况的说明和描述。包含不适合在其他列中显示但十分重要的额外信息。

  • Using index:表示使用索引,如果只有 Using index,说明他没有查询到数据表,只用索引表就完成了这个查询,这个叫覆盖索引。

  • Using where:表示条件查询,如果不读取表的所有数据,或不是仅仅通过索引就可以获取所有需要的数据,则会出现 Using where。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liuyuinsdu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值