美文网首页
MySQL索引学习

MySQL索引学习

作者: hu1991die | 来源:发表于2017-10-11 11:30 被阅读51次

    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、参考资料

    相关文章

      网友评论

          本文标题:MySQL索引学习

          本文链接:https://www.haomeiwen.com/subject/neniyxtx.html