索引是一种可以帮助我们快速检索数据库中的数据的数据结构
接下来,我们具体聊聊mysql中的索引
索引分类
- 从存储结构上来划分:BTree索引(B-Tree或B+Tree索引),hash索引,full-index全文索引,R-Tree索引
- 从应用层次来分:普通索引,唯一索引,符合索引
- 根据数据中的物理顺序与键值的逻辑(索引)顺序关系:聚集索引,非聚集索引(除了聚集索引,其他的都是非聚集索引)
普通索引:即一个索引只包含单个列,一个表中可以有多个单列索引
唯一索引:索引列必须唯一,但允许有空值
复合索引:即一个索引包含多个列
详解
hash索引
实现
基于哈希表实现,只有精确匹配索引所有列的查询才有效,对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),并且hash索引将所有的哈希码存储在索引中,同时在索引表中保存执行每个数据行的指针
优点
由于hash索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位。
缺点
- hash索引 仅仅能满足“=”,“IN”,“<=>”查询,不能使用范围查询
由于Hash索引比较的是进行hash运算之后的hash值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的hash算法处理之后的hash值得大小关系,并不能保证和hash运算前完全一致
- hash索引无法被用来避免数据得排序操作
由于hash索引存放的是经过Hash计算之后的hash值,而且Hash值得大小关系并不一定和运算前的键值完全一致,所以数据库无法利用索引的数据来避免任何排序运算
- hash索引不能利用部分索引键查询
对于组合索引,hash索引在节算hash值得时候是组合索引合并后再一起计算hash值,而不是单独计算hash值。所以通过组合索引的前面一个或几个索引键进行查询的时候,hash索引无法被利用
B-Tree索引
实现
B-Tree索引能加快数据的访问速度,因为存储引擎不再需要进行全表扫描来获取数据,数据分布在各个节点
节点结构
每个节点都是一个二元数组:[key,data],所有节点都可以存储数据,key为索引key,data为除key之外的数据
检索原理
首先从根节点进行二分查找,如果找到则返回对应节点的data,否则对相应区间的指针指向节点递归进行查找,直到找到节点或未找到节点返回null指针。
B-Tree意味着所有的值都是按顺序存储的,并且每一个叶子到根的距离相同,很适合查找范围数据
缺点
- 插入删除新的数据记录会破坏B-Tree的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持B-Tree性质。造成IO操作频繁
- 区间查找可能需要返回上层节点,导致查找效率降低
B+Tree索引
是B-Tree的改进版,同时也是mysql数据库所采用的存储结构。非叶子节点不存储data,只存储key。只有叶子节点才存储data
mysql中的B+Tree
在经典的B+Tree的基础上进行了优化,增加了顺序访问指针。在B+Tree的每个叶子节点增加了一个指向相邻叶子节点的指针,形成了带有顺序访问指针的B+Tree。这样就提高了区间访问性能。如果要查询key为从18到49的所有数据记录,只需要顺着节点和指针顺序遍历就可以一次性访问到所有的数据节点
为什么mysql选择B+Tree索引?B+Tree索引有什么好处
索引本身也很多,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。这样的话,索引查找过程中就要产生IO消耗,相对与内存存取,IO存取的消耗高,所以索引的结构要尽量减少磁盘IO存取,提升索引效率。
聚簇索引
聚簇索引是对磁盘上实际数据重新组织以按指定的一个或多个列的值排序的算法。特点是存储数据的顺序和索引顺序一致。
即聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。
innerDB中的聚簇索引
innerdb按聚簇索引的形式存储数据,所以它的数据布局有很大的不同。它存储数据的结构如下
注:在innerDB中,索引B+Tree的叶子节点中存储了整行数据的是主键索引,也称之为聚集索引。
而索引B+Tree的叶子节点存储了主键的值的是非主键索引,也称之为非聚簇索引
mysql中的聚簇索引和B+Tree索引的结构是一样的,并且索引的数据文件需要按照主键聚集,因此innerDB中要求表必须有主键,如果没有指定mysql会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这样的列,mysql会为表生成一个6字节长整型作为主键
联合索引
两个或更多列上的索引叫联合索引,联合索引又叫复合索引。对于复合索引,mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部分,但只能是最左侧部分。例如索引是key index(a,b,c),可以支持a|a,b|a,b,c 3种组合进行查找,但不支持b,c进行查找。当最左侧字段是常量引用时,索引就十分有效
索引使用
- 需要加索引的字段要在where条件种
- 数据量少的字段不需要加索引
- 如果where条件中是or关系,加索引不起作用
- 复合最左前缀匹配原则
为什么要使用联合索引
- 减少开销
建一个联合索引(col1,col2,col3),实际上相当于建了(col1),(col1,col2),(col1,col2,col3)三个索引。每多一个索引,都会增加写操作的开销和磁盘空间的开销。对于大量数据的表,使用联合索引会大大减少开销
- 覆盖索引
对于联合索引(col1,col2,col3),如果有如下sql
sql select col1,col2,col3 from test where col1 = 1 and col2=2
那么mysql可以直接通过遍历索引取得数据,而无需回表。