关于

MySQL 数据库存储数据最终是以文件的形式存储到硬盘的,在程序中使用要把磁盘文件中的数据读到内存中
执行一次IO的时间可以执行40万条指令(如果以 CPU 的指令执行效率来比较的话) 数据库量百万千万级数据,如每次io 9毫秒的时间显然是个灾难
所以查找数据时把磁盘IO次数控制在一个很小的数量级,一个高度可控的多路搜索树就是 B + 树
树的高度决定着io的次数,如果没有索引 没有索引则检索过程变成了顺序查找,O(n)的时间复杂度几乎是不能忍受 ,每个磁盘块都要发生一次IO(单个磁盘块中不可能存储太多数据) 效率会特别差

一、底层实现原理和优化
      在数据结构中,最常见的搜索结构就是二叉搜索树和AVL树(高度平衡的二叉搜索树,,当数据量比较大时,都会由于树的深度过大而造成I/O读写过于频繁,进而导致查询效率低下
      mysql的索引数据结构采取的是B+树
      B+树索引并不能根据键值找到具体的行数据,B+树索引只能找到行数据锁在的页,然后通过把页读到内存,再在内存中查找到行数据
      B+树,它的树高是恒定(可以控制在3到5层),它的渐进复杂度是恒定的
     索引若采用哈希:
         可以通过hash值定位具体的位置,效率高,但是不能进行模糊查询 范围查询
     一个索引的是否优秀判断的依据是 IO渐进复杂度
     索引若采用二叉树:
         若是一个斜二叉树,查询速度和全表扫描没有区别,树高
     索引若采用平衡二叉树:
         太深了:深度决定者io的次数,而io耗时大
         太小了:结点存储的信息太小了,从而导致频繁的io操作
     索引若采用红黑树:
          比二叉树相对来说会好一些。它会有一个因子会控制树高,无论二叉搜索树还是AVL树,当数据量比较大时,都会由于树的深度过大而造成I/O读写过于频繁
     索引若采用多路平衡二叉树:(B-Tree B树):
        (1)每个节点中有key,也有data,而每一个页的存储空间是有限的,如果data数据较大时就会导致每个节点(即一个页)能存储的key的数量很小
        (2)当存储的数据量很大时,同样1会导致B-Tree的深度较大,增加查询时的磁盘I/O次数,进而影响查询效率
     B+Tree叶子结点是顺序的,相邻结点存在顺序引用
         1:B+Tree拥有B-Tree的优点,深度浅,数据块大
         2:因为只在叶子结点存储数据,从而导致扫全表的能力强,因为叶子结点是顺序的,从而导致排序功能更强

二、B+树更适合B树
      磁盘读写代价更低:
          B+tree的内部结点相对B 树更小,相对来说IO读写次数也就降低了
      查询效率更加稳定:
          任何关键字的查找必须走一条从根结点到叶子结点的路,所有关键字查询的路径长度相同,导致每一个数据的查询效率相当
      主要原因:
          B+树只要遍历叶子节点就可以实现整棵树的遍历 方便扫库,而且在数据库中基于范围的查询是非常频繁的,而B树只能中序遍历所有节点,效率太低

三、文件索引和数据库索引使用B+树的原因
      文件与数据库都是需要较大的存储,也就是说,它们都不可能全部存储在内存中,故需要存储到磁盘上
      数据库系统巧妙利用了局部性原理与磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入
      而红黑树这种结构,高度明显要深的多,并且由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性。
      B+树最大的好处:只要遍历叶子节点就可以实现整棵树的遍历 方便扫库,而且在数据库中基于范围的查询是非常频繁的。
                                而B树只能中序遍历所有节点,效率太低

四、索引的优点
     加快数据的检索速度
     加速表和表之间的连接;
     通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
     使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间;(有序)

五、索引的缺点
     时间方面:创建索引和维护索引要耗费时间 ,R U D时,索引也要动态的维护,这样就降低了数据的维护速度;
     空间方面:索引需要占物理空间

六、索引类型
     普通索引、唯一索引、组合索引 、全文索引 。不一一介绍了
     HASH 哈希索引 (MEMORY支持)

七、什么数据应该添加索引 (索引干两件事:检索和排序)
     1.频繁作为查询条件的字段
     2.查询中排序的字段 (有序)
     3.主外键关系的字段 (可以加快连接的速度)
     4.经常需要根据范围进行搜索的列上 (索引已经排序,其指定的范围是连续的)
     5.经常需要排序的列上
     注意:对于大的文本字段甚至超长字段 可以用前缀索引

八、索引注意事项
     1.注意组合索引键列顺序
     2.正确使用索引 遵循SARG规则
        SARG 用于限制搜索的一个操作,是一个值的范围内的匹配或者两个以上条件的AND连接
        SARG规则 如果使用not 或者 <>,最好转换成别的方法
        不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>;、!<;、!>;、NOT EⅪSTS、NOT IN、NOT LIKE等,
       另外还有索引字段不能用函数.
       如:Name=’张三’ and 价格>5000 符号SARG,
       而:Name=’张三’ or 价格>5000 则不符合SARG。
       使用or会引起全表扫描。尽量不要对建立了索引的字段,作任何的直接处理

       2.1.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,表字段时不能允许为null的列 可设置默认值
           select id from t where num is null 可以在num上设置默认值0
           应改为:
           select id from t where num=0
      2.2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
      2.3.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描 (少用or)
           select id from t where num=10 or num=20
           应改为:
           select id from t where num=10    union all     select id from t where num=20
     2.4.in 和 not in 也要慎用,因为IN会使系统无法使用索引,而只能直接搜索表中的数据
           select id from t where num in(1,2,3)   对于连续的数值,能用 between 就不要用 in 了
           应改为:
           select id from t where num between 1 and 3
     2.5.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描
           select id from t where substring(name,1,3)='abc'--name以abc开头的id
           select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
           应改为:
           select id from t where name like 'abc%' (通配符 前缀索引)
           select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
     2.5.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引
     2.6.用not exists都比not in要快
           not in 那么内外表都进行全表扫描,没有用到索引;
           not extsts 的子查询依然能用到表上的索引
     2.7.能用UNION ALL就不要用UNION
           UNION ALL不执行SELECT DISTINCT函数(去重),这样就会减少很多不必要的资源
     2.8.前缀索引
           char/varchar太长全部做索引的话,效率太差,存在浪费
           无法使用其前缀索引做ORDER BY和GROUP BY,也无法使用前缀索引做覆盖扫描

群交流(262200309)
原文地址:https://www.cnblogs.com/webster1/p/12404805.html