文章目录
- 1 概述
- 1.1 介绍
- 1.2 优缺点
- 2 索引结构
- 2.1 B+Tree索引
- 2.2 hash索引
- 2.3 对比
- 3 索引分类
- 3.1 通用分类
- 3.2 InnoDB存储引擎分类
- 4 思考题
- 后记
1 概述
1.1 介绍
索引是帮忙MySQL 高效获取数据的数据结构(有序)。在数据之外,数据系统还维护着满足特定查找算法的数据结构。这些数据结构以某种方式音乐(指向)数据,这样就可以在这些数据结构傻姑娘实现高级查找算法,这种数据结构就是索引。
1.2 优缺点
优势 | 缺点 |
---|---|
提高数据检索的效率,将低数据IO成本 | 索引列需要占有空间 |
通过索引列对数据进行排序,将低数据排序的成本,将低CPU的消耗 | 索引大大提高查询效率,在更新的时候需要维护索引,效率降低 |
2 索引结构
MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,按照存储结构分类主要包含以下几种:
索引结构 | 描述 |
---|---|
B+Tree索引 | 最常见的索引类型,大部分引擎都支持B+树索引 |
Hash索引 | 底层数据结构是用哈希表实现的,只有精确匹配索引列的查询才有效,不支持范围查询 |
R-tree(空间索引) | 空间索引是MYISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少 |
Full-text(全文索引) | 是一种通过建立倒排索引,快速匹配文档的方式。类似于Lucene,Solr,ES |
2.1 B+Tree索引
B+树(B+tree)是一种常用的平衡树数据结构,也是MySQL中常用的索引结构之一,用于提高数据访问效率。B+树与B树类似,但有着更高的磁盘块利用率和更好的查询性能。
B+树的特点如下:
- 所有关键字都出现在叶子结点的链表中,且链表中的关键字恰好是按照大小顺序排列的。
- 所有非叶子结点可看成是索引部分,结点中仅含有其子树根结点中的最大(或最小)关键字。
- 每个叶子结点都带有指向其后继结点的指针,加速区间访问或遍历。
相对于B树,B+树的区别在于:
- 非叶子结点仅仅是索引,不存储数据。
- 所有数据都存储在叶子结点中。
- 叶子结点之间都有指针相连,可以轻易地进行区间查找或遍历。
B+树通常应用于磁盘上的存储,因为它能够更好地利用磁盘块,减少了磁盘I/O操作的次数。当数据量较大时,B+树能够更快地查询到数据。
在MySQL中,使用B+树索引结构的表通常有一个叶子节点包含所有数据的指针,以及多个索引节点来加速查找。这些索引节点仅仅是用来定位叶子节点的位置,不存储具体的数据。B+树索引可以提高查询性能,特别是对于范围查询等操作,但对于大量的更新操作,B+树索引会比较慢,因为更新数据时需要不断地调整索引结构。
如下图2.1-1所示:
B+树一个节点对应一页/块,页为InnoDB引擎逻辑存储结构中固定大小的存储结构。每个非叶子结点不用存储数据,可以存储更多的key,同样数据量大情况下,树的高度自然更低,查询效率相应更高。
InnoDB引擎逻辑存储结构,如下图2.1-2所示:
2.2 hash索引
哈希索引(hash index)基于哈希表实现。哈希索引通过Hash算法(直接定址法、平方取中法、折叠法、除数取余法、随机数法)将数据库的索引列数据转换成定长的哈希码作为key,将这条数据的行的地址作为value一并存入Hash表的对应位置。
在MySQL中,只有Memeory引擎显式的支持哈希索引,这也是Memory引擎表的默认索引结构,Memeory同时也支持B-Tree索引。并且,Memory引擎支持非唯一哈希索引,如果多个列的哈希值相同(或者发生了Hash碰撞),索引会在对应Hash键下以链表形式存储多个记录地址。
Hash索引的特点:
- Hash索引只用于对等比较(=,in),不支持范围查询(between,>,<,…);
- 无法利用索引完成排序操作;
- 查询效率高,通常只需要一次检索就可以了。
存储引擎支持:
在MySQL重,支持hash索引的是Memory引擎,而Inno DB中具有自适应hash功能,hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的。
2.3 对比
问题1:为什么Inno DB存储引擎选择使用B+Tree索引结构?
- B+Tree,相对于二叉树,层数少,搜索效率高。
- 相比于B-Tree非叶子结点不存储数据,每个结点(页)能够存储更多的键,那么相同数据量大情况下层级更低,效率更高;
- 相比于Hash,它支持范围查询。
3 索引分类
3.1 通用分类
主要分类如下表3-1所示:
分类 | 含义 | 特点 | 关键字 |
---|---|---|---|
主键索引 | 针对于表中主键创建的索引 | 默认自动创建,只能由一个 | PRIMARY |
唯一索引 | 限制同一表中某数据列值不能重复 | 可以有多个 | UNIQUE |
常规索引 | 快速定位特定数据 | 可以有多个 | |
全文索引 | 全文索引查找的是文本中的关键词,而不是比较索引中的值 | 可以有多个 | FULLTEXt |
- 主键索引(Primary Key Index):主键是一种用于唯一标识每个记录的索引,通常使用B+树作为索引结构,可以快速定位到指定的记录。主键索引在查询、更新、删除等操作时具有高效性能。
- 唯一索引(Unique Index):唯一索引要求索引列的值不能重复,通常用于保证数据的唯一性和数据完整性。唯一索引通常也使用B+树作为索引结构,与主键索引类似。
- 普通索引(Normal Index):普通索引是最基本的索引类型,它可以加速查询特定列或多个列的值。普通索引也常使用B+树作为索引结构。
- 全文索引(Full-Text Index):全文索引可以用于高效地进行文本匹配和搜索。它不像普通索引只能匹配关键字的前缀,而是能够匹配关键字的任意位置。全文索引通常采用特殊的数据结构,如倒排索引等。
需要根据具体场景和查询需求来选择合适的索引类型。选择适当的索引类型可以有效地提高数据库的查询效率和性能
3.2 InnoDB存储引擎分类
InnoDB存储引擎中,根据所有的存储形式,又可以分为以下两种:
分类 | 含义 | 特点 |
---|---|---|
聚集索引 | 将数据存储和索引放在一起,索引结构的叶子结点保存了行数据 | 必须有,而且只有一个 |
二级索引 | 将数据和索引分开存储,索引结构的叶子结点关联的是对应的主键 | 可以存在多个 |
聚集索引选取规则:
- 如果存在主键,主键索引就是聚集索引;
- 如果不存在主键,将使用第一个唯一索引作为聚集索引;
- 如果表没有主键或者没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。
示例表及结构如下图3.2-1所示:
- 聚集索引为主键索引,叶解决存储主键对应行数据;
- name字段建立的索引为二级索引,叶结点存储主键。
接下来我们该SQL语句select * from user where name='Arm'
的执行过程,如下图3.2-2所示:
具体过程如下:
- 根据name字段查找,先根据name=‘Arm’到name字段到二级索引进行匹配查找,查找结果为对应的主键10;
- 在根据主键id=10在id字段的聚集索引(主键索引)匹配查找,找到对应的行记录row。
回表查询:先在二级索引中查找数据,找到主键。然后在到聚集索引中根据主键获取数据的方式,称为回表查询。
4 思考题
示例表同#3中user表
- 以下2条SQL语句那个执行效率高?为什么
select * from user where id=10;
select * from user where name='Arm';
-- id为主键,name字段创建有索引
回答:第一条SQL语句执行效率高;
解析:
- 第一条查询字段id为主键,通过聚集索引根据主键匹配查询相应的数据行;而第二条查询根据name字段,需要先通过二级索引查询出主键,在通过聚集索引根据id(主键字段)查询对应数据。
- InnoDB的主键索引B+tree指定高度可以存储多少条记录?
B+tree存储结构如下图4-1所示所示:
假设: 一行数据大小为1k,一页中可以存储16行这样的数据。InnoDB的指针占用6个字节的空
间,假设主键即使为bigint,占用字节数为8。 高度为2:
n ∗ 8 + ( n + 1 ) ∗ 6 = 16 ∗ 1024 , 算出 n 约为 1170 ; 1171 ∗ 16 = 18736 n*8+(n+1)*6=16*1024, 算出n约为 1170; 1171* 16 = 18736 n∗8+(n+1)∗6=16∗1024,算出n约为1170;1171∗16=18736 也就是说,如果树的高度为2,则可以存储 18000 多条记录。
高度为3:
1171 * 1171 * 16 = 21939856 也就是说,如果树的高度为3,则可以存储 2200w 左右的记录。一行数据大小为rowSize,一页大小为16k,InnoDB的指针占有6字节大小,主键类型占有大小为primarySize,高度为h,则存储记录公式为:
非叶结点计算主键数量: k e y s ∗ p r i m a r y S i z e + ( k e y s + 1 ) ∗ 6 = 16 ∗ 1024 keys*primarySize+(keys+1)*6=16*1024 keys∗primarySize+(keys+1)∗6=16∗1024
叶结点计算可以存储多少记录: k e y s h − 1 ⋅ 16 ∗ 1024 r o w S i z e = r e c o r d s \quad keys^{h-1}\cdot\frac{16*1024}{rowSize}=records keysh−1⋅rowSize16∗1024=records
- 大小单位为字节,keys为主键数量。
后记
如果小伙伴什么问题或者指教,欢迎交流。
❓QQ:806797785
参考链接:
[1]ChatGPT
[2]MySQL数据库视频[CP/OL].2020-04-16.p66-73.
[3]MySQL相关(番外篇)- innodb 逻辑存储结构.[CP/OL].