题目:
- 索引是什么?
- 索引的优缺点?
- MySQL 索引类型都有什么?
- 索引的底层实现?
- 为什么索引结构默认使用 B+Tree?
- 聚簇索引和非聚簇索引区别?
- 非聚簇索引什么时候不会回表查询?
- 联合索引是什么?为什么需要注意联合索引的顺序?
1. 索引是什么?
在 MySQL 中,索引是一种特殊的数据库结构,由数据表中的一列或多列组合而成,可以用来快速查询数据表中有某一特定值的记录,索引中包含着对数据库所有记录的引用指针。
2. 索引的优缺点?
索引的优点:
(1)通过使用索引可以大大加快数据的查询速度(使用索引最主要的原因)
(2)可以在查询过程中,使用优化隐藏器,提高系统性能
优化隐藏:
对查询语句,查询处理器创建了可以提高性能的执行规划。然而,如果对某一个特定的查询语句例如检索、插入、删除、修改,查询处理器没有创建最好的执行规划,那么用户可以在查询语句中增加优化隐藏来影响查询处理器创建出的最优的执行规划。优化隐藏就是指在执行查询语句、使用多表连接检索或者指定查询语句操作的对象表时,明确地指出应该使用的查询方法、连接算法或者对表的操作方式。
索引的缺点:
(1)时间方面来看,创建维护索引需要耗费时间,具体表现为在对表中数据进行增删改的时候,索引也需要动态维护,降低增删改的执行效率
(2)空间方面来看,索引的存储也需要占据物理空间
3. MySQL 索引类型都有什么?
- 按存储结构来划分,可分为 :BTree索引(包括 B-Tree 和 B+Tree 索引),Hash 索引,FullText index 全文索引,R-Tree 索引
全文索引: 通过建立倒排索引,极大的提升检索效率,解决判断 字段是否包含 的问题。倒排索引也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。(在MySQL 5.6版本以前,MyISAM存储引擎支持全文引擎。在5.6版本中,InnoDB存储引擎加入了对全文索引的支持,但是不支持中文全文索引。在5.7.6版本,MySQL内置了ngram全文解析器,用来支持亚洲语种的分词。
- 从应用层次来划分,可分为:普通索引,唯一索引和复合索引
- 普通索引:一个索引只包含单个列,一个数据库可包含多个单列索引
- 唯一索引:索引值必须唯一(允许有 null 值)
- 复合索引:多个值组成一个索引,用于组合搜索,效率高于索引合并
- 从数据的存储方式划分,根据数据的物理顺序与键值的逻辑关系:分为聚簇索引,非聚簇索引
- 聚簇索引:不是一种单独存在的索引类型,是一种数据存储方式。细节取决于不同的实现,以 InnoDB 数据库为例,其聚簇索引就是在同一个结构中中保持 B-Tree 索引和数据行
- 非聚簇索引:不是聚簇索引的就是非聚簇索引
4. 索引的底层实现?
1. Hash 索引
基于哈希表实现,只有精确匹配索引的所有列查询才有效。对于每行数据,存储引擎都会对其计算一个哈希码(hash code),并且 Hash 索引将所有的哈希码存储在索引中,同时在索引表中保持指向每个数据行的指针。
2. B-Tree 索引
B-Tree 结构里每个节点包含了索引值和表记录的信息,数据分布在各个节点之中,可以加快访问速度,不需要扫描全表获取数据。
3. B+Tree 索引
B-Tree 的改进,是 MySQL 使用的索引存储结构。数据都存储在叶子节点上,在叶子节点间增加了顺序访问指针,相较于 B-Tree 每次都需要从根节点开始查找,B+Tree 存储的结构范围查找效率更高。
B+Tree 性质:
- 叶子节点保存全部关键字信息以及指向这些关键字记录的指针,叶子节点本身依照关键字自小而大顺序连接。(这种结构会在上层非叶子节点存储一部分冗余数据,但是这样的缺点是可以容忍的,因为冗余的都是索引数据,不会对内存造成大的负担)
- 非叶子节点都是索引部分,仅含子树的最大最小关键字
- B+Tree 中含两个头指针,一个是树的根节点,一个是最小关键字的叶节点
5. 为什么索引结构默认使用 B+Tree?
B+Tree:
B+树的磁盘读写代价更低:
B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B(B-)树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。
B+树更加适合区间查询:
由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,必须从根节点开始进行一次中序遍历,所以B+树更加适合区间查询的情况,所以通常B+树用于数据库索引。
Hash:
- Hash索引虽然可以快速定位,但是没有顺序,IO复杂度高;
- 适合等值查询,如=、in()、,Hash索引在查询等值时非常快 ,但是不支持范围查询;
- 因为不是按照索引值顺序存储的,就不能像B+Tree索引一样利用索引完成排序 ;
- 因为Hash索引始终索引的所有列的全部内容,所以不支持部分索引列的匹配查找 ;
- 如果有大量重复键值得情况下,哈希索引的效率会很低,因为存在哈希碰撞问题
二叉树:
树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高
红黑树:
树的高度随着数据量增加而增加,IO代价高。
6. 聚簇索引与非聚簇索引的区别:
聚簇索引:
聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分,每张表只能拥有一个聚簇索引。
非聚簇索引:
在聚簇索引之上创建的索引称之为非聚簇索引,非聚簇索引访问数据总是需要二次查找。非聚簇索引叶子节点存储的不再是行的物理位置,而是主键值。通过非聚簇索引首先找到的是主键值,再通过主键值找到数据行的数据页,再通过数据页中的Page Directory找到数据行。
回表
对于 InnoDB存储引擎 来说,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。回表的操作属于随机IO。需要回表的次数越多,即随机IO次数越多,我们就越倾向于使用全表扫描 。
注意:MyISAM无论主键索引还是二级索引都是非聚簇索引,而InnoDB的主键索引是聚簇索引,二级索引是非聚簇索引。我们自己建的索引基本都是非聚簇索引。
7. 非聚簇索引一定会回表查询吗?
如果查询语句所要求的字段全部命中了索引,那么就不必再进行回表查询。
覆盖索引:
一个索引包含(覆盖)所有需要查询字段的值
举个简单的例子,假设我们在学生表的成绩上建立了索引,那么当进行select score from student where score > 90的查询时,在索引的叶子节点上,已经包含了score 信息,不会再次进行回表查询。
8. 联合索引是什么?为什么需要注意联合索引中的顺序?
MySQL可以使用多个字段同时建立一个索引,叫做联合索引。在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引。
具体原因:
MySQL使用索引时需要索引有序,假设现在建立了”name,age,school”的联合索引,那么索引的排序为: 先按照name排序,如果name相同,则按照age排序,如果age的值也相等,则按照school进行排序。
当进行查询时,此时索引仅仅按照name严格有序,因此必须首先使用name字段进行等值查询,之后对于匹配到的列而言,其按照age字段严格有序,此时可以使用age字段用做索引查找,以此类推。因此在建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询需求频繁或者字段选择性高的列放在前面。此外可以根据特例的查询或者表结构进行单独的调整。