MySQL索引总结
看了很多关于索引的博客,讲的大同小异。但是始终没有让我明白关于索引的一些概念,如B-Tree索引,Hash索引,唯一索引….或许有很多人和我一样,没搞清楚概念就开始研究B-Tree,B+Tree等结构,导致在面试的时候答非所问!
一、什么是索引
索引是帮助MySQL高效获取数据的数据结构。
二、索引能干什么
索引非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。索引能够轻易将查询性能提高好几个数量级,总的来说就是可以明显的提高查询效率。
三、索引的分类
从存储结构划分:
BTree索引(B-Tree或B+Tree索引)、Hash索引、full-index全文索引、R-Tree索引。这里所描述的是索引存储时保存的形式,
从应用层次来分:
普通索引、唯一索引、复合索引
从数据的物理顺序与键值的逻辑(索引)顺序关系:
聚集索引、非聚集索引
平时讲的索引类型一般是指在应用层次的划分
就像手机分类:安卓手机,IOS手机 与 华为手机,苹果手机,OPPO手机一样。
- 普通索引
即一个索引只包含单个列,一个表可以有多个单列索引 - 唯一索引
索引列的值必须唯一,但允许有空值 - 复合索引
多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
聚簇索引(聚集索引):并不是一种单独的索引类型,而是一种数据存储方式。具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B-Tree索引(技术上来说是B+Tree)和数据行。
非聚簇索引:不是聚簇索引,就是非聚簇索引
四、索引的底层实现
mysql默认存储引擎innodb只显式支持B-Tree( 从技术上来说是B+Tree)索引,对于频繁访问的表,innodb会透明建立自适应hash索引,即在B树索引基础上建立hash索引,可以显著提高查找效率,对于客户端是透明的,不可控制的,隐式的。
4.1 Hash索引
基于哈希表实现,只有精确匹配索引所有列的查询才有效,对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),并且Hash索引将所有的哈希码存储在索引中,同时在索引表中保存指向每个数据行的指针。
4.2 B-Tree索引
B-Tree能加快数据的访问速度,因为存储引擎不再需要进行全表扫描来获取数据,数据分布在各个节点之中。
4.3 B+Tree索引
MySQL使用B+Tree,B-Tree的改进版本,同时也是数据库索引索引所采用的存储结构。
- 数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都指向相邻的叶子节点的地址。
- 相比B-Tree来说,进行范围查找时只需要查找两个节点,进行遍历即可。而B-Tree需要获取所有节点,相比之下B+Tree效率更高。
五、案例讲解
案例:假设有一张学生表,id为主键
id | name | birthday |
---|---|---|
1 | Tom | 1996-01-01 |
2 | Jann | 1996-01-04 |
3 | Ray | 1996-01-08 |
4 | Michael | 1996-01-10 |
5 | Jack | 1996-01-13 |
6 | Steven | 1996-01-23 |
7 | Lily | 1996-01-25 |
5.1 MyISAM引擎实现
二级索引也是这样实现的
5.2 在InnoDB中的实现
二级索引也是这样实现的
六、为什么索引结构默认使用B+Tree
为什么索引结构默认使用B+Tree,而不是Hash,二叉树,红黑树
B-tree:因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少(有些资料也称为扇出),指针少的情况下要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低;
Hash:虽然可以快速定位,但是没有顺序,IO复杂度高。
二叉树:树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高。
红黑树:树的高度随着数据量增加而增加,IO代价高。
七、为什么官方建议使用自增长主键作为索引
结合B+Tree的特点,自增主键是连续的,在插入过程中尽量减少页分裂,即使要进行页分裂,也只会分裂很少一部分。并且能减少数据的移动,每次插入都是插入到最后。总之就是减少分裂和移动的频率。
插入连续的数据
插入非连续的数据
八、简单总结
- MySQL使用B+Tree作为索引数据结构
- B+Tree在新增数据时,会根据索引指定列的值对旧的B+Tree做调整
- 从物理存储结构上说,B-Tree和B+Tree都以页(4K)来划分节点的大小,但是由于B+Tree中中间节点不存储数据,因此B+Tree能够在同样大小的节点中,存储更多的key,提高查找效率。
- 影响MySQL查找性能的主要还是磁盘IO次数,大部分是磁头移动到指定磁道的时间花费
- MyISAM存储引擎下索引和数据存储是分离的,InnoDB索引和数据存储在一起
- InnoDB存储引擎下索引的实现,(辅助索引)全部是依赖于主索引建立的(辅助索引中叶子结点存储的并不是数据的地址,还是主索引的值,因此,所有依赖于辅助索引的都是先根据辅助索引查到主索引,再根据主索引查数据的地址)
- 由于InnoDB索引的特性,因此如果主索引不是自增的(id作主键),那么每次插入新的数据,都很可能对B+Tree的主索引进行重整,影响性能。因此,尽量以自增id作为InnoDB的主索引