MySQL技术总结第二篇

此篇着重讲MySQL存储引擎中的索引和算法

写在前面:

数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。如果索引太多,应用程序性能就会受影响,如果索引太少,查询性能又会受影响。所以找到平衡点至关重要。

InnoDB存储引擎支持以下索引:
B+树索引
哈希索引

其中InnoDB的哈希索引是自适应的,即自动为表生成哈希索引。InnoDB存储引擎会监控对表上各索引页的查询。如果观察到建立哈希索引可以带来速度提升,则建立哈希索引,称之为自适应哈希索引(Adaptive Hash Index, AHI)。AHI是通过缓冲池的B+树页构造而来,因此建立的速度很快,而且不需要对整张表构建哈希索引。InnoDB存储引擎会自动根据访问的频率和模式来自动地为某些热点页建立哈希索引。

一,数据结构与算法

如何在索引中快速查询到数据呢?一般的存储引擎底层都用了树结构,提起树的查找效率,那就要从二分查找法说起。
二分查找法

int l;
int r;
while(l < r){
int mid = l + (r-l)/2;
if(query1)
r = m;
else
l = m+1;
}

通过二分查找,树可以做到查找数据时间为O(logN),关于树结构在此不再赘述,可以参考数据结构之树

二,B+树与B+树索引

B+树是为磁盘或其他直接存取辅助设备设计的一种多路平衡查找树。在B+树中,所有记录节点都是按键值大小顺序放在同一层的叶子节点上,由各叶子节点指针进行连接。非叶节点不存储实际值,只存储指针。
B+树索引高度一般在2-4层,即查找某一键值的行记录最多需要2-4次。

数据库B+树索引可分为聚集索引(InnoDB)和辅助索引(MyISAM)。

聚集索引

聚集索引一般是表中的主键索引,如果表中没有显示指定主键,则会选择表中的第一个不允许为NULL的唯一索引,如果还是没有的话,就采用Innodb存储引擎为每行数据内置的6字节ROWID作为聚集索引。

InnoDB存储引擎表是索引组织表,即表中数据按照主键顺序存放。而聚集索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的即为整张表的行记录数据,所以聚集索引的叶节点也叫做数据页。每个数据页通过一个双向链表连接,按照主键顺序排序,由于通过双向链表可维护,物理存储上可以同样不按照主键存储。
聚集索引的另一个好处是,对于主键的排序查找和范围查找速度很快,叶子节点的数据就是用户所要查询的数据,范围查询只要查找主键某一范围的数据,通过也足节点上层中间节点就可得到页的范围,之后读取数据页。

辅助索引

辅助索引(非聚集索引)(secondary index)叶子节点不包含行记录的全部数据。叶子节点除了包含键值以外,每个叶子节点的索引中还包含书签,用来确定InnoDB中索引对应的行数据。其中据说堆表比索引组织表要快,所以对于频繁更新列和索引,推荐使用辅助索引。同样对于大数目的不同值,InnoDB不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。

聚集索引和辅助索引不同的是叶子节点存放的是否是一整行的信息。

三,哈希算法与哈希索引

哈希算法是一种常见算法,时间复杂度为O(1)。
InnoDB存储引擎使用哈希算法来对字典进行查找,冲突机制采用链表方式。Hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引。

虽然 Hash 索引效率高,但是 Hash 索引本身由于其特殊性也带来了很多限制和弊端,主要有以下这些:

(1)Hash 索引仅仅能满足"=",和"<=>"等值查询,不能使用范围查询。
如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;当然了,这个前提是,键值都是唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和Hash运算前完全一样。

(2)Hash 索引无法被用来避免数据的排序操作。
由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且Hash值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算;

(3)Hash 索引不支持多列联合索引的最左匹配规则;
对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。

(4)Hash 索引在任何时候都不能避免表扫描。
前面已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。

(5)B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题

备注:复合索引

用户可以在多个列上建立索引,这种索引叫做复合索引(组合索引);     复合索引在数据库操作期间所需的开销更小,可以代替多个单一索引,mysql在按照最左前缀的索引匹配原则,且会自动优化 where 条件的顺序。

例子:

创建索引     create index idx1 on table1(col1,col2,col3)      查询     select * from table1 where col1= A and col2= B and col3 = C     这时候查询优化器,不在扫描表了,而是直接的从索引中拿数据,因为索引中有这些数据,这叫覆盖式查询,这样的查询速度非常快; 

对于复合索引,在查询使用时,最好将条件顺序按找索引的顺序,这样效率最高;     select * from table1 where col1=A AND col2=B 可以     如果使用 where col3=B AND col1=A 或者 where col2=B 将不会使用索引.

当条件中只有 col2=B AND col1=A 时,会自动转化为 col1=A AND col2=B,所以依然会使用索引。

下面条件将能用上部分组合索引查询:

  • A>5 AND B=2 ——当范围查询使用第一列,查询条件仅仅能使用第一列
  • A=5 AND B>6 AND C=2 ——范围查询使用第二列,查询条件仅仅能使用前二列

猜你喜欢

转载自blog.csdn.net/wannuoge4766/article/details/95499523