2024年10月12日
前言
越来越多的公司正在使用MySQL作为数据库来进行数据存储,想必索引(Index)大家也都不会陌生,可能所有的开发人员都知道索引是为了加速数据查询才存在的。无论是在开发中还是面试中,索引出现的频率都是特别的高,所以无论是为了工作还是面试,我们都要搞清楚索引的原理,只有掌握了它的原理才能应付各种问题。接下来我们就简单来了解一下到底MySQL的索引是什么。
索引是为了帮助MySQL存储引擎高效的获取排好序的数据结构。简单一点理解就是快速查找排好序的数据结构,用我们生活中的例子做类比的话就是字典的目录(虽然某些索引类型来讲不是很贴切)。
索引的几个概念:
可以作为索引的数据结构有很多,比如:二叉树、红黑树、B-Tree、Hash表、B+Tree等,那么MySQL的索引有哪几种类型呢?MySQL最常用的索引类型有两种:B+Tree和Hash,这里我们把B-Tree这种类型也一起看一下。
B+Tree这种索引的类型其实是在B-Tree的基础上做了升级,算是一个高级进阶版本的B-Tree
介绍B+Tree之前,首先要说一下B-树(B-Tree),学过数据结构的应该都清楚B树的性质,B-树是一棵多路平衡查找树,与二叉树、红黑树想必降低了树的高度,也就相当于降低了IO次数。
而B+Tree相对于B-树的结构上做了一些改变:
1.每个中间节点不保存数据,只用来索引,也就意味着所有非叶子节点的值都被保存了一份在叶子节点中
2.叶子节点之间根据自身的顺序增加指针做链接
这样做的好处就是我们查找的次数将会变得更少,因为我们都知道MySQL默认情况下,表空间中的页大小都为 16KB,如果我们只存储索引不存储数据的话,那么显而易见大小相同的情况下B+Tree存储的索引数量将会更大,相同数据量的情况下会减少了树的高度,也就会减少IO的次数,因为IO次数越多我们所需花费的查找成本将越高。
B+Tree的时间复杂度为O(H)=O(logdN)(H为树高, d为出度, N为数据量),假设一棵出度为200,数据量为200万的树,我们可以算出树的高度仅为3,也就意味着我们只需3次IO就可以读取到我们想要查找的数据。
Hash索引是基于Hash表实现的,只有查询条件精确匹配hash索引中的所有列的时候,才能用到Hash索引。哈希算法时间复杂度为O(1),且不只存在于索引中,每个数据库应用中都存在该数据结构,由于其特殊的结构,其检索的效率也是非常高,索引的检索可以一次定位,不会像B+Tree那样需要从根节点一直查找到叶子节点这样多次IO才查找到最终需要的数据。Hash表索引类型在开发中用到的场景不多,所以这里不做详细的介绍,如果需要详细了解可以在MySQL官网或者相关的论坛找到详细资料。
按照上述所看到的特点Hash索引类型(Memory存储引擎默认索引类型)查询的效率要远远高于B+Tree,可是为什么MySQL的InnoDB和MyISAM默认都采用的是B+Tree来作为索引呢?
接下来我们看看一下Hash索引类型有哪些不足:
InnoDB虽然和MyISAM都是采用的B+Tree来实现的索引,但是InnoDB的索引存储方式和MyISAM还有些不同,之前的文章我们说过这两种存储引擎的文件存储方式不同(MySQL存储引擎),重大区别是 InnoDB 的数据文件本身就是索引文件。
在InnoDB 中,表数据文件本身就是按 B+Tree 组织的一个索引结构,这棵树的叶点data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。
上图中的索引就是这张表的主键索引,我们找到索引就找到了数据,我们称这种索引为聚簇索引。
InnoDB存储引擎要求必须有主键索引(聚簇索引的特征),如果没有显示的指定主键索引,那么MySQL会自动选择一个可以唯一标识数据的列作为唯一索引,如果表中没有唯一的列来标识数据的话,那么MySQL将会自动维护一个长整形的隐含字段来作为主键,所以为了能更清晰的显示表的主键,在使用InnoDB作为表的存储引擎时我们最好还是主动创建采用自增的主键。因为 InnoDB 数据文件本身是一棵B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持 B+Tree 的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页,有益于提高效率。
InnoDB存储引擎中的辅助索引与主键索引唯一不同的地方就是,辅助索引的叶子节点存储的不是数据行,而是对应的主键,所以需要再根据主键查询出具体数据,这种查询方式称为“回表查询”。
MyISAM都是采用的也是B+Tree来实现的索引,但是由于其数据文件和索引文件是分开进行存储我们称为非聚簇索引。索引都是采用B+Tree索引结构但是与InnoDB存储引擎下还有些许不同。它的叶子节点存储的是将不再是数据而是数据行对应的指针,也就是说MyISAM在查询数据的时候需要先根据索引查找到数据的指针,再根据指针查找数据,相对于InnoDB来说多了一次IO。
MyISAM存储引擎允许没有任何索引和主键的表存在。MyISAM的主键索引与辅助索引是没有区别的,辅助索引的叶子节点也是存储的数据行的指针,所以不存在“回表查询”的说法。
以上为MySQ索引原理的理解和总结,只有掌握了基本原理才能明白如何去解决问题和优化解决方案,下一篇我们再讲解一下MySQL的索引类型及索引优化的东西。希望这篇文章可以帮助正在学习技术的你,如有不足之处欢迎评论指正,一起学习一起进步!