写会MySQL索引

本文首发于我的微信公众号:《andyqian》,期待您的关注!

前言

继上篇《读懂MySQL执行计划》后,在文章末尾,咱们谈到了索引的概念,那么,今天咱们就一块儿来聊一聊MySQL索引。数据库

什么是索引?

百度百科是这样描述的:服务器

索引是为来加速对表中数据行中的检索而建立的一种分散的数据结果,时针对表而创建的,它是由数据页面之外的索引页面组成,每一个索引页中的行都含有逻辑指针,以便加速检索物理数据微信

其实,索引的概念你们都很清楚,也知道索引可以提高查询效率,但大部分童鞋在怎么建索引,建在哪些字段上有如下常见误解:架构

  • 新建表时不须要建索引,后续才添加索引函数

  • where条件后的字段均建索引测试

  • 简单SQL不须要索引,联合查询才须要索引编码

  • 联合索引的顺序是where条件后字段的前后顺序spa

  • 对于区分度小的字段上也新建索引,如状态,性别等字段等。.net

索引区分度

在说上述问题以前,咱们先来看看另外一个概念,就是区分度。设计

区分度: 指字段在数据库中的不重复比

区分度在新建索引时有着很是重要的参考价值,在MySQL中,区分度的计算规则以下:

字段去重后的总数与全表总记录数的商。

例如:

select count(distinct(name))/count(*) from t_base_user;

结果以下:

count(distinct(name))/count(*)
1.0000

其中区分度最大值为1.000,最小为0.0000,区分度的值越大,也就是数据不重复率越大,新建索引效果也越好,在主键以及惟一键上面的区分度是最高的,为1.0000,在状态,性别等字段上面的区分度值是最小的。 (这个就要看数据量了,若是只有几条数据,这时区分度还挺高的,若是数据量多,区分度基本为0.0000。也就是在这些字段上添加索引后,效果也不佳的缘由。)

值得注意的是: 若是表中没有任何记录时,计算区分度的结果是为空值,其余状况下,区分度值均分布在0.0000-1.0000之间。

如何建索引

   (一)  : 区分度
我的强烈建议, 建索引时,必定要先计算该字段的区分度,缘由以下:

1. 单列索引
能够查看该字段的区分度,根据区分度的大小,也能大概知道在该字段上的新建索引是否有效,以及效果如何。区分度越大,索引效果越明显。

2.多列索引(联合索引)
多列索引中其实还有一个字段的前后顺序问题,通常是将区分度较高的放在前面,这样联合索引才更有效,例如:

select * from t_base_user where name="" and status=1;

像上述语句,若是建联合索引的话,就应该是:

alter table t_base_user add index idx_name_status(name,status);

而不是:

alter table t_base_user add index idx_status_name(status,name);

(二) 最左前缀匹配原则
  MySQL会一直向右匹配直到遇到范围查询(>、<、between、like)就中止匹配,好比

select * from t_base_user where type="10" and created_at<"2017-11-03" and status=1, (该语句仅做为演示)

在上述语句中,status就不会走索引,由于遇到<时,MySQL已经中止匹配,此时走的索引为:(type,created_at),其前后顺序是能够调整的,而走不到status索引,此时须要修改语句为:

select * from t_base_user where type=10 and status=1 and created_at<"2017-11-03"

便可走status索引。

(三) 函数运算
  不要在索引列上,进行函数运算,不然索引会失效。由于b+树中存的都是数据表中的字段值,但进行检索时,须要把全部元素都应用函数才能比较,显然成本太大。

(四) 扩展优先
  扩展优先,不要新建索引,尽可能在已有索引中修改。以下:

select * from t_base_user where name="andyqian" and email="andytohome"

在表t_base_user表中已经存在idx_name索引,若是须要加入idx_name_email的索引,应该是修改idx_name索引,而不是新建一个索引。

误解纠正

  上面说了,如何新建索引,如今咱们就能够来回答,在第一步中存在的误解了。

误解一: 新建表时不须要创建索引,后续才加索引

答: 一个好的数据表设计,在一开始就要考虑索引的建立,而不是等到后续出问题了,影响业务使用了,才新建索引来救场,并且后续建立索引的成本也相对高不少。(这就是给生产事故留下生根发芽的机会呀)

误解二: where条件后的字段均建索引

答: 这个误解比较常见,但where条件后的字段不须要所有创建索引,过多的索引,也会致使索引文件剧增,也还达不到指望中的效果。详细请参考上述新建索引的小节。

误解三: 简单SQL不须要创建索引,联合查询采创建索引

答: 这个误解就得好好说说了,如今互联网公司特别是B/S架构下,业务逻辑均剥离在代码逻辑层,到最后SQL层面,其实都是一些简单的SQL,只有些许链接查询,更多的仍是单表操做,(C/S架构中有不少在SQL层面的写逻辑的),你说这些语句简不简单。

误解四: 联合索引的顺序是where条件后字段的前后顺序

答: 咱们刚才说过,联合索引的顺序,是根据最左前缀原则,以及区分度来区分的,和where条件后字段的前后顺序无关。

误解五: 对于区分度较小的字段新建索引

答: 在区分度较小的字段上新建索引,基本无效,还会增长大量的索引文件,你说是否是得不偿失。

索引重不重要?

  上面介绍了MySQL索引的概念,新建索引时的一些技巧。这么理论的东西,对于平时没有使用或使用比较少的童鞋,此时对索引的重要性可能还没那么直观,那么,我就来讲说我在索引上吃过的亏,踩过的坑!同时也是未建索引常见问题!

0. 致使慢查询
这个问题但是未建索引的常客哦,(这里也还有不少细节呢,如: 隐式类型转换等等)

1. 致使服务超时

场景 :
  在某次上线时,做为服务提供者,提供服务给业务方使用。一开始觉得就提供一个简单的服务,也已经测试完成,内心还在窃喜,今天总算能够早早回家了!
描述 :
  实际一上线,在生产环境中致使业务方请求调用时,并且每次请求均超时,数据也已落地,此时只能review代码,最后发现生产中有个慢查询致使,活活的花费了10多秒,这个语句有多简单呢,你绝对想不到,就是一个简单的单表where查询。

你说这种缘由致使服务不可用,你说冤不冤,气不气!(这也是我为何说,一个好的数据表设计,从一开始就要考虑新建索引了)。

2. 数据库服务器CPU 100%

在查询频率比较高的SQL上,若是出现未建索引,致使慢查询的话,那但是会致使数据库服务器CPU 100%,影响但是整个系统哦。

小结
上面说了好几类,因为没创建索引而致使的问题,轻则致使慢查询,影响系统效率,重则,致使CPU 100%,影响整个系统的使用,看到这里,你说索引重不重要?

最后

  上面简单说了,索引是什么?有什么用,以及创建索引时的一些技巧,还着重说了,索引的重要性。那么索引这么重要,在平时编码时如何避免呢? 如下是我我的的建议:

  1. 在建表时就应该考虑添加索引,如: 外键字段,等等。
  2. 在写完SQL后,必定要查看执行计划。尽可能避免全表扫描。
  3. 若是是已有表中添加索引,必定要先计算该字段的区分度。
  4. 联合索引,将区分度大放在前面。
  5. 听从MySQL左列前缀优先原则

最后的最后:   你们辛苦一周,立刻就是周末了,祝你们周末愉快!

                                                  这里写图片描述

                                                             扫码关注,一块儿进步

                                                我的博客: http://www.andyqian.com

相关文章
相关标签/搜索