zoukankan      html  css  js  c++  java
  • 数据库索引学习

    一、索引介绍

    数据库索引调优是一项技术活,不能只靠理论,由于实际情况千变万化,并且各种数据库本身存在非常复杂的机制,如查询优化策略和各种引擎的实现等。但同一时候这些理论是索引调优的基础。唯独在明确理论的基础上,才干对调优策略进行合理判断并了解其背后的机制,然后结合实践中不断的实验和摸索。

    索引事实上就是在数据库存储数据之外。还维护着另外的满足某种查询算法的数据结构。这些数据结构再以某种方式指向真实的存储数据。然后在现有的数据结构上实现高速查询。(找了张非常不错的二叉树的图来理解索引,如今大多的索引都是B+树的结构。基本上没有使用二叉树的)。



    二、数据库操作时间占用都在IO操作上

    索引本身也非常大。不可能所有存储在内存中,往往以索引文件的形式存储在磁盘上。

    所以索引查找过程中就要产生磁盘I/O消耗,相对于内存存取。I/O存取的消耗要高出好多好多,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的复杂度。

    换句话说。索引的结构组织要尽量降低查找过程中磁盘I/O的存取次数。而B+树结构在实际的应用中刚好满足降低物理I/O操作的要求,来胜任索引结构再合适只是了(以下介绍)。


    三、随机IO、顺序IO


         数据库查询大部分时间都消耗在了I/O上,而内存I/O要比物理I/O快的多。所以 一次查询操作物理I/O的次数非常大程度决定了查询的终于时间。

    同一时候物理I/O的种类又分了 顺序、随机I/O, 顺序和随机。是指本次IO给出的初始扇区地址。和上一次IO的结束扇区地址,是不是全然连续的。或者相隔不多的,假设是,则本次IO应该算是一个连续IO。假设相差太大。则算一次随机IO。连续IO,由于本次初始扇区和上次结束扇区相隔非常近,则磁头差点儿不用换道或换道时间极短。假设相差太大,则磁头须要非常长的换道时间,假设随机IO非常多。导致磁头不停换道,效率大大降底。

        随机訪问的特点是每次IO请求的数据在磁盘上的位置跨度非常大(如:分布在不同的扇区)。因此N个非常小的IO请求会以N次IO请求才干获取到对应的数据。

        顺序訪问的特点尾随机訪问相反,它请求的数据在磁盘的位置是连续的。当系统发起N个很小的IO请求(如:1K)时,由于一次IO是有代价的,系统会取完整的一块数据(如4K、8K),所以当第一次IO完毕时,兴许IO请求的数据可能已经有了。

    这样能够降低IO请求的次数。

        随机訪问的特点是每次IO请求的数据在磁盘上的位置跨度非常大(如:分布在不同的扇区)。因此N个非常小的IO请求会以N次IO请求才干获取到对应的数据。

        顺序訪问的特点尾随机訪问相反。它请求的数据在磁盘的位置是连续的。当系统发起N个很小的IO请求(如:1K)时,由于一次IO是有代价的。系统会取完整的一块数据(如4K、8K),所以当第一次IO完毕时。兴许IO请求的数据可能已经有了。这样能够降低IO请求的次数。


    四、文件系统和数据库系统中经常使用的B+ 树结构

    在学校时候理解数据库中的查询就觉得是一般的顺序查找。如今再回忆这样的复杂度为O(n)的算法在数据量非常大的情况下简直不敢想想,那么多牛逼的查询算法像二分查找、二叉树查找等 在实际的应用上还真没有好好琢磨过。找了些对照B-Tree、B+Tree结构的资料(下图非常好诠释了两种结构的差别)。


    1、B-Tree、B+Tree主要差别:
        B+树的非叶子结点仅仅包括导航信息。不包括实际的值,全部的叶子结点和相连的节点使用链表相连,便于区间查找和遍历。


    2、B+ 树的长处在于:

    • B+树在非叶子节点上不存储data,仅仅存储key。因此在载入到内存中时能够存放很多其它的key;
    • 非叶子节点特别小,出度大的情况下非叶子节点少,能够全然载入到内存中降低 IO次数; 
    • 数据key值存放的更加紧密,具有更好的空间局部性。

      因此訪问叶子几点上关联的数据也具有更好的缓存命中率。

    • B+树的叶子结点都是相链的。因此对整棵树的便利仅仅须要一次线性遍历叶子结点就可以。并且因为数据顺序排列并且相连,所以便于区间查找和搜索,能够被连续载入。
    • 而B树则须要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好;
    • 可是B树也有长处,其长处在于。因为B树的每个节点都包括key和value。因此常常訪问的元素可能离根节点更近。因此訪问也更迅速;



    五、组合索引使用场景

    常索引有 唯一索引、主键索引、聚集索引。有时候为了了很多其它的提高mysql效率可建立组合索引,遵循“最左前缀“原则。最左前缀:顾名思义,就是最左优先。比如,对于表title(id,no,name,age)我们创建了以三个字段的组合多列索引(no,name,age),相当于创建了(no)单列索引。(name,fname)组合索引以及(no,name,age)组合索引。

      其它的不多说了,这次主要是对组合索引的学习,以下列出组合索引“最左前缀”的场景 (就以上表title为例、通过查看运行计划是否走了索引):

    1、能够走索引的全列匹配

    • 当查询条件 where no=n and name=b and age =20  或者 where no=n  and  name=b  或者where no=n 都能够走进索引。
    • 项mysql查询优化器会自己主动调整where子句的条件顺序以使用适合的索引,所以把条件顺序做下调整不会影响结果 如:where age=20  and  name=b  and  no=n 相同能够走到索引;
    • 在条件中使用“in”语法相同能够走到索引;


    2、最左前缀。中间的一个条件未提供

    如 where no = n  and age = 20  少了索引中间列 name 。这时候仅仅用到了索引的第一列no ,后面age尽管也在索引中,因为缺少name列 无法和左前缀连接。


    3、查询条件没有指明 索引第一列 

         假设少了索引的第一列no  如:where name = ‘jeck’ and age = 20 这样不匹配最左前缀,就无法走索引了。


    4、索引字段中用到了 %的模糊匹配语法

         假设在某列中使用了 % 模糊匹配。要看%的位置推断能否走到索引, %在字符串的最后则能够使用索引 ,如:
    where  no = 1  and name like  'luc%’
    ; 可是,假设%在前面就不行  如:where no = 1 and name like ‘%cy’ ;


    5、范围查找 

         假设在sql中用到了 < 、 >的范围查找 ,且仅仅有一个范围列的 就能够走到索引,否则都走不到索引 。
    如:
    where no < 20  and   name = ‘lucy’ ; 


    6、查询结果中含有函数表达式

       有函数表达式也无法走到索引;


    六、建索引注意事项 

    1、某个列作为条件筛选的结果仍然非常大

    像”性别”属性,数据库中仅仅会有男、女两种类型。这时候全然不是必需使用索引,反而会导致查询结果更糟糕。由于假设不走索引将是个全表的顺序查询(一个随机IO)。可是这时候走了索引而且还返回了一个表的非常大部分记录,会出现非常多的随机IO,无形中添加了操作的IO。

    2、组合索引字段顺序

         所以在使用组合索引时候,索引字段的顺序对索引结构影响不大。可是会影响到终于的排序,终于影响以部分字段作为查询条件时候会不会走上索引的问题。

    3、哪些场景不适合建索引

         对于记录比較少的表,添加索引不会带来速度的优化反而浪费了存储空间,由于索引是须要存储空间的,并且有个致命缺点是对于update/insert/delete的每次运行。字段的索引都必须又一次计算更新;

    4、建索引考虑的条件

         索引尽量少、索引尽量短、合理组织索引字段顺序、索引字段更新频率尽量少、索引应该是经常使用查询字段且能高速定位少量记录。

     


    很多其它学习參考:


  • 相关阅读:
    hdu 1028 Ignatius and the Princess III (n的划分)
    CodeForces
    poj 3254 Corn Fields (状压DP入门)
    HYSBZ 1040 骑士 (基环外向树DP)
    PAT 1071 Speech Patterns (25)
    PAT 1077 Kuchiguse (20)
    PAT 1043 Is It a Binary Search Tree (25)
    PAT 1053 Path of Equal Weight (30)
    c++ 常用标准库
    常见数学问题
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/6877486.html
Copyright © 2011-2022 走看看