转自 由浅入深理解索引的实现(2)
如果要看“由浅入深理解索引的实现(1)”,请点这里
。
教科书上的B+Tree是一个简化了的,方便于研究和教学的B+Tree。然而在数据库实现时,为了
更好的性能或者降低实现的难度,都会在细节上进行一定的变化。下面以InnoDB为例,来说说
这些变化。
04
- Sparse Index中的数据指针
在“由浅入深理解索引的实现(1)”中提到,Sparse Index中的每个键值都有一个指针指向
所在的数据页。这样每个B+Tree都有指针指向数据页。如图Fig.1所示:
Fig.1
如果数据页进行了拆分或合并操作,那么所有的B+Tree都需要修改相应的页指针。特别是
Secondary B+Tree(辅助索引对应的B+Tree), 要对很多个不连续的页进行修改。同时也需要对
这些页加锁,这会降低并发性。
为了降低难度和增加更新(分裂和合并B+Tree节点)的性能,InnoDB 将 Secondary B+Tree中
的指针替换成了主键的键值。如图Fig.2所示:
Fig.2
这样就去除了Secondary B+Tree对数据页的依赖,而数据就变成了Clustered
B+Tree(簇
索引对应的B+Tree)独占的了。对数据页的拆分及合并操作,仅影响Clustered B+Tree.
因此
InnoDB的数据文件中存储的实际上就是多个孤立B+Tree。
一个有趣的问题,当用户显式的把主键定义到了二级索引中时,还需要额外的主键来做二级索引的
数据吗(即存储2份主键)? 很显然是不需要的。InnoDB在创建二级索引的时候,会判断主键的字段
是否已经被包含在了要创建的索引中。
接下来看一下数据操作在B+Tree上的基本实现。
- 用主键查询
直接在Clustered B+Tree上查询。
- 用辅助索引查询
A. 在Secondary B+Tree上查询到主键。
B. 用主键在Clustered B+Tree
可以看出,在使用主键值替换页指针后,辅助索引的查询效率降低了。
A. 尽量使用主键来查询数据(索引遍历操作除外).
B. 可以通过缓存来弥补性能,因此所有的键列,都应该尽量的小。
- INSERT
A. 在Clustered B+Tree上插入数据
B. 在所有其他Secondary B+Tree上插入主键。
- DELETE
A. 在Clustered B+Tree上删除数据。
B. 在所有其他Secondary B+Tree上删除主键。
- UPDATE 非键列
A. 在Clustered B+Tree上更新数据。
- UPDATE 主键列
A. 在Clustered B+Tree删除原有的记录(只是标记为DELETED,并不真正删除)。
B. 在Clustered B+Tree插入新的记录。
C. 在每一个Secondary B+Tree上删除原有的数据。
(有疑问,看下一节。)
D. 在每一个Secondary B+Tree上插入原有的数据。
- UPDATE 辅助索引的键值
A. 在Clustered B+Tree上更新数据。
B. 在每一个Secondary B+Tree上删除原有的主键。
C. 在每一个Secondary B+Tree上插入原有的主键。
更新键列时,需要更新多个页,效率比较低。
A. 尽量不用对主键列进行UPDATE操作。
B. 更新很多时,尽量少建索引。
05 – 非唯一键索引
教科书上的B+Tree操作,通常都假设”键值是唯一的“。但是在实际的应用中Secondary Index是允
许键值重复的。在极端的情况下,所有的键值都一样,该如何来处理呢?
InnoDB 的 Secondary B+Tree中,主键也是此键的一部分。
Secondary Key = 用户定义的KEY + 主键。如图Fig.3所示:
Fig.3
注意主键不仅做为数据出现在叶子节点,同时也作为键的一部分出现非叶子节点。对于非唯一键来说,
因为主键是唯一的,Secondary Key也是唯一的。当然,在插入数据时,还是会根据用户定义的Key,
来判断唯一性。按理说,如果辅助索引是唯一的(并且所有字段不能为空),就不需要这样做。可是,
InnoDB对所有的Secondary B+Tree都这样创建。
还没弄明白有什么特殊的用途?
有知道的朋友可以帮忙解答一下。
也许是为了降低代码的复杂性,这是我想到的唯一理由。
06 – <Key, Pointer>对
标准的
B+Tree的每个节点有K个键值和K+1个指针,指向K+1个子节点。如图Fig.4:
Fig.4(图片来自于WikiPedia)
而在“由浅入深理解索引的实现(1)”中Fig.9
的B+Tree上,每个节点有K个键值和K个指针。
InnoDB的B+Tree也是如此。如图Fig.5所示:
Fig.5
这样做的好处在于,键值和指针一一对应。我们可以将一个<Key,Pointer>对看作一条记录。
这样就可以用数据块的存储格式来存储索引块。因为不需要为索引块定义单独的存储格式,就
降低了实现的难度。
- 插入最小值
当考虑在变形后的B+Tree上进行INSERT操作时,发现了一个有趣的问题。如果插入的数据的健
值比B+Tree的最小键值小时,就无法定位到一个适当的数据块上去
(<Key,Pointer>中的Key
代表了子节点上的键值是>=Key的)。例如,在Fig.5的B+Tree中插入键值为0的数据时,无法
定位到任何节点。
在标准的B+Tree上,这样的键值会被定位到最左侧的节点上去。这个做法,
对于Fig.5中的
B+Tree也是合理的。Innodb的做法是,将每一层(叶子层除外)的最左侧节点
的第一条记录标
记为最小记录(MIN_REC).在进行定位操作时,任何键值都比标记为MIN_REC的键值大。因此0
会被插入到最左侧的记录节点上。如Fig.6所示:
Fig.6
07 – 顺序插入数据
Fig.7是B-Tree的插入和分裂过程,我们看看有没有什么问题?
Fig.7(图片来自于WikiPedia)
标准的B-Tree分裂时,将一半的键值和数据移动到新的节点上去。原有节点和新节点都保留一半
的空间,用于以后的插入操作。当按照键值的顺序插入数据时,左侧的节点不可能再有新的数据插入。
因此,会浪费约一半的存储空间。
解决这个问题的基本思路是:分裂顺序插入的B-Tree时,将原有的数据都保留在原有的节点上。
创建一个新的节点,用来存储新的数据。顺序插入时的分裂过程如Fig.8所示:
Fig.8
以上是以B-Tree为例,B+Tree的分裂过程类似。InnoDB的实现以这个思路为基础,不过要复杂
一些。因为顺序插入是有方向性的,可能是从小到大,也可能是从大到小的插入数据。所以要区
分不同的情况。如果要了解细节,可参考以下函数的代码。
btr_page_split_and_insert();
btr_page_get_split_rec_to_right();
btr_page_get_split_rec_to_right();
InnoDB的代码太复杂了,有时候也不敢肯定自己的理解是对的。因此写了一个小脚本,来打印InnoDB数
据文件中B+Tree。这样可以直观的来观察B+Tree的结构,验证自己的理解是否正确。
推荐关联性文章:
分享到:
相关推荐
### 浅入深出ElasticSearch构建高性能搜索架构 #### 快速学习ElasticSearch **ElasticSearch**是一款基于Lucene的分布式搜索和分析引擎,适用于全文检索、结构化数据检索等多种场景。本章节旨在帮助初学者快速掌握...
数据结构的学习从浅入深,旨在逐步提升我们对计算机存储和处理信息的理解,为编写高效的算法打下坚实基础。 数据结构主要包括以下几个关键类别: 1. 线性数据结构:这是最基本的数据结构,如数组、链表、栈和队列...
用途:为想要更深入理解MATLAB数组操作和应用的开发者和学习者提供全面指南。 资源描述: 这份资源将带您从基础到高级层面深入探索MATLAB中的数组操作和应用。通过逐步讲解,您将了解如何利用MATLAB强大的数组功能...
首先,理解词索引表的原理至关重要。词索引表通常是一个关联数组或哈希表,其中键是单词,值是这些单词在文本中出现的位置列表。这种数据结构允许我们快速定位到特定单词的所有实例,大大提高了文本处理的效率。 在...
这个课程的目的是让学生理解数据库系统的基础,包括其设计、实现和管理。课件内容可能涵盖了多个方面,从基本概念到复杂的查询技术。 一、数据库的定义 数据库(Database)是一种组织和存储数据的系统,它允许用户...
本"jsp学习文档从浅到深"提供了从基础到高级的全面学习路径,旨在帮助初学者和有经验的开发者深化对JSP的理解。 **CHM(Compiled HTML Help)** 文件是一种由Microsoft开发的帮助文件格式,它将一系列HTML页面、...
例如,使用函数指针可以实现回调函数的功能,通过指针传递大型数据结构可以减少复制的成本,使用指针数组可以轻松实现多级索引和复杂的数据映射。所有这些操作在汇编语言中可能需要复杂的指令和更多的代码,而在...
《数据库系统实现(第二版)》是斯坦福大学教授精心编撰的一本经典教材,它深入浅出地探讨了数据库系统的构建与设计。这本教材的PPT版本为学习者提供了一个直观、易于理解的学习资源,有助于加深对数据库理论与实践...
"深入浅出SQL Server数据库开发随书光盘"是针对该系统的一款配套学习资源,包含了与书中理论知识相辅相成的实践代码。通过这本书和光盘中的内容,读者可以深入理解SQL Server的各个方面,包括但不限于数据库设计、...
《深入浅出SQL Server 2005开发,管理与应用实例》这本书是数据库管理员、开发者和学习者深入了解SQL Server 2005的重要资源。配套光盘内容通常包括书中提到的实际示例、练习文件、数据库脚本以及可能的视频教程,...
严蔚敏版的《数据结构》是一本被广泛使用的经典教材,它深入浅出地介绍了各种数据结构及其算法的实现。这个压缩包文件包含了该教材配套的实现程序,为学习者提供了实践操作的机会。 1. **数组**:数组是最基本的...
总的来说,这个压缩包提供了学习数据结构的实践平台,通过C语言实现经典数据结构和算法,可以帮助读者深入理解数据结构的工作原理,并且培养解决实际问题的能力。无论是初学者还是有一定经验的程序员,都能从中获益...
严蔚敏教授的《数据结构》教材是该领域内广为流传的经典之作,它深入浅出地讲解了各种数据结构的原理和实现方法。这个压缩包包含的全部代码实现,是学习和理解数据结构的宝贵资源,特别是对于使用C语言进行编程的...
2. **全文索引结构与Lucene实现**:Lucene是Java开发的开源全文检索库,它提供了创建、维护和搜索索引的API。搜索引擎使用Lucene来构建倒排索引,这是一种高效的数据结构,用于快速定位包含特定词汇的文档。 3. **...
这份资源包含了严蔚敏教授在教材中提到的各种数据结构及其相关算法的详细实现,旨在帮助学习者深入理解和掌握数据结构的原理与应用。 数据结构是计算机科学中处理信息存储和组织方式的学科,它是算法设计的基础,...
本文深入浅出地介绍了哈希表的基本概念、工作原理,尤其是如何解决哈希碰撞问题,包括开放地址法和链地址法两种方法,并给出了Python和C语言的实例实现代码。 适合人群:对于想深入理解和掌握哈希表这一重要数据结构...
6. **散列表**:散列表(哈希表)是一种通过散列函数将键映射到数组索引的数据结构,实现快速查找。C语言中,散列表的实现涉及到了数组和冲突解决策略(如开放寻址法和链地址法)。 7. **排序**:排序是将一组数据...
在这个压缩包中,包含的是用C语言实现的部分数据结构算法,这对于初学者理解并掌握数据结构的概念及其应用至关重要。 1. **数组**:数组是最基础的数据结构,它在内存中连续存储相同类型的数据。在C语言中,数组...