MySQL索引学习

2017-10-11  本文已影响51人  hu1991die

1、什么是索引?

索引是一种数据结构
索引的目的在于提高查询效率

2、索引的原理

通过不断的缩小数据查找的范围筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是我们总是通过同一种查找方式来锁定数据

通俗点说,我们拿出一本新华字典,它的目录实际上就是一种索引:非聚集索引,我们可以通过目录迅速定位我们要查的字。而字典的内容部分一般都是按照拼音排序的,这实际上又是一种索引:聚集索引。

3、索引的优点与劣势

3.1、创建索引的好处:

  • 1、加快经常被搜索字段的搜索速度。
  • 2、利用索引的唯一性来控制记录的唯一性
  • 3、等

3.2、创建索引的坏处:

  • 1、额外的存储空间(单列索引占原表5%至15%空间,想象一下如果为一个表创建三四个索引)
  • 2、额外的创建和维护时间:执行数据修改操作(INSERT、UPDATE、DELETE)产生索引维护

4、索引的数据结构

一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,每次查找数据时把磁盘IO次数控制在一个很小的数量级,最好是常数数量级。那么我们就想到如果一个高度可控的多路搜索树是否能满足需求呢?就这样,b+树应运而生

5、Btree数据结构

使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。而B+tree是B-tree的一个变种,大名鼎鼎的MySQL就普遍使用B+tree实现其索引结构。

image.png image.png

6、Btree的查找过程

首先从根节点进行二分查找,如果找到则返回对应节点的data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或找到null指针,前者查找成功,后者查找失败。
真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高

7、联合索引

当b+树的数据项是复合的数据结构,比如(name,age,sex)的时候,b+数是按照从左到右的顺序来建立搜索树的,比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性。

8、最左前缀匹配

多列索引还有另外一个优点,它通过称为最左前缀(Leftmost Prefixing)的概念体现出来。继续考虑前面的例子,现在我们有一个firstname、lastname、age列上的多列索引,我们称这个索引为fname_lname_age。当搜索条件是以下各种列的组合时,MySQL将使用fname_lname_age索引:

  • 1、firstname,lastname,age
  • 2、firstname,lastname
  • 3、firstname

从另一方面理解,它相当于我们创建了(firstname,lastname,age)、(firstname,lastname)以及(firstname)这些列组合上的索引

9、建索引的几大原则

  • 1.最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
  • 2.=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
  • 3.尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录
  • 4.索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);
  • 5.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可

10、索引选择与前缀索引

索引虽然加快了查询速度,但索引也是有代价的:索引文件本身要消耗存储空间,同时索引会加重插入、删除和修改记录时的负担,另外,MySQL在运行时也要消耗资源维护索引,因此索引并不是越多越好。
第一种情况是表记录比较少,例如一两千条甚至只有几百条记录的表,没必要建索引,让查询做全表扫描就好了。2000为分界线
另一种不建议建索引的情况是索引的选择性较低。所谓索引的选择性(Selectivity),是指不重复的索引值(也叫基数,Cardinality)与表记录数(#T)的比值:
Index Selectivity = Cardinality / #T

11、用不用索引

索引至少会带来如下的overhead
额外的创建时间
额外的存储空间(单列索引占原表5%至15%空间,想象一下如果为一个表创建三四个索引)
额外的维护时间
这一切只为了一个目的:减少在small range query的情况下的query time。如果是大range query 返回1%以上的数据,这情况下索引的意义不大

12、选用哪种索引

low selectivity情况下 比如parent column为性别,bitmap index什么的可以考虑
high selectivity可以用btree什么的来维持二分查找的查找效率

13、公司小贷系统优化

  • 1、部分like模糊匹配,只要是涉及到前后都进行%通配符模糊查询的都修改成全值匹配
  • 2、将一些or并行查询改成in
  • 3、count统计可以考虑去除
  • 4、关于进件列表查询的一些条件选择,可以统计业务人员最常用的一些组合是哪些,然后将这些组合建立联合索引,根据最左匹配规则
  • 5、根据索引的选择性优化部分索引(基数判断,status字段)
  • 6、explain分析工具
  • 7、用in或者exists来替换or
  • 8、用union来替换or(适用于索引列)
  • 9、列类型为字符串类型,查询时没有用单引号引起来
  • 10、在where查询语句中对字段进行NULL值判断
  • 11、在where查询语句中使用表达式
  • 12、先limit再进行join连接查询,还是先join再limit

14、例子说明

image.png
Status这个索引效果不是很大
image.png
我们可以考虑给USERNAME这个字段建一个索引
image.png
另外,我们还可以调查统计业务人员的操作习惯,哪些查询条件是常用的,然后可以考虑给这些条件一起建一个组合索引(需要考虑最左匹配原则,where条件后面)
image.png
索引优化之前的延时统计
image.png
索引优化之后的延时统计
image.png
根据业务情况创建组合索引
image.png
查询已处理的进件单列表(没有使用索引)
image.png
使用索引之后
image.png
image.png

ok,到这里已经结束了,感谢各位的耐心!前段时间被安排了一个性能优化的任务,经过这几天的学习做了一个小小的总结,希望能够帮到大家,非常感谢!

15、参考资料

上一篇下一篇

猜你喜欢

热点阅读