教科书上的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:

(图片来自于wiki)

而在"由浅入深理解索引的实现(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

标准的B-Tree分裂时,将一半的键值和数据移动到新的节点上去。原有节点和新节点都保留一半的空间,用于以后的插入操作。当按照键值的顺序插入数据时,左侧的节点不可能再有新的数据插入。因此,会浪费约一半的存储空间。

解决这个问题的基本思路是:分裂顺序插入的B-Tree时,将原有的数据都保留在原有的节点上。创建一个新的节点,用来存储新的数据。顺序插入时的分裂过程如Fig.8所示:

Fig.8

以上是以B-Tree为例,B+Tree的分裂过程类似。InnoDB的实现以这个思路为基础,不过要复杂一些。因为顺序插入是有方向性的,可能是从小到大,也可能是从大到小的插入数据。所以要区分不同的情况。

原文地址:

http://www.mysqlops.com/2011/12/20/understanding_index2.html

转载于:https://www.cnblogs.com/gomysql/p/3636217.html

由浅入深理解索引的实现(2)【转】相关推荐

  1. 由浅入深理解索引的实现

      由浅入深理解索引的实现 http://blog.duplicatedcode.com/programme/224.html 背景知识 - B-Tree & B+Tree http://en ...

  2. Database之SQLSever:SQL命令实现理解索引、规则、默认概念及其相关案例之详细攻略

    Database之SQLSever:SQL命令实现理解索引.规则.默认概念及其相关案例之详细攻略 目录 SQL命令实现理解索引.规则.默认概念 索引 规则

  3. MYSQL专题-由简到繁理解索引结构

    大家可能都听过数据库索引,当然作为开发者来说其实大部分时间也用过索引.但是可能有的人知道索引是干什么的,但是对于索引的结构却不是很了解.所以这篇博客我会谈谈对索引结构的一些知识以及分享如何从零开始一层 ...

  4. 深入浅出理解索引结构

    (一)深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonc ...

  5. mongodb系列02-------深入理解索引原理

    点击有惊喜 之前对index的了解仅仅是停留在使用上面,一直都不太清楚index的原理没,那段时间专门看了一下,这里我梳理一下 如果我们想要理解索引的原理,我们首先要了解一种最基本的数据结构Btree ...

  6. 数据结构 实验14(1-2班):(深入理解索引存储结构)三元组存储的稀疏矩阵建立行列索引并求鞍点

    目录 前言: 需求分析: 难点分析: 代码和思路详解: 三元组表的头文件: 建立索引思路: 什么是三元组表的索引: 结合题意实现索引表: 建立索引表的代码实现: 索引表的结构体定义: 索引表的创建思路 ...

  7. 深入浅出理解索引结构[zt]

    (一)深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonc ...

  8. python装饰器由浅入深_由浅入深理解Python装饰器

    前提知识: 1.Python里函数也是一种对象: def shout(word="yes"): return word.capitalize()+"!" pri ...

  9. mysql 二级索引原理_你真的理解索引吗?从数据结构层面解析mysql索引原理

    索引数据结构 数据页基本结构 : 从上图可以推断出,查询某条记录关键步骤只有2个:定位到数据页 定位到记录 如果没有索引,查询某条记录只能先依次遍历数据页,确定记录所在的数据页之后:再从数据页中通过 ...

最新文章

  1. 使用Python+OpenCV预测年龄与性别
  2. 微信小程序使用template模板
  3. “写画”与“惊春”:王艾画展和当代诗人朗诵会
  4. Java编程基础阶段笔记 day 07 面向对象编程(上)
  5. 想在客户端脚本中引用CHECKBOXLIST中的CHECKBOX项?
  6. [导入]画带阴影效果的文字
  7. python上传文件接口_Python接口测试文件上传实例解析
  8. PLC1200通过CB1241RS485通讯走modbus rtu连接昆仑通态
  9. VSCode 下载速度慢问题解决
  10. Java过滤微信昵称特殊字符
  11. 计算机二级常用口诀,2017计算机二级考试重点
  12. Educational Codeforces Round 61 (Rated for Div. 2) D. Stressful Training //二分
  13. 笔记本控制台开启热点
  14. 数字化转型——技术转型推动业务转型(第一次讨论稿)
  15. vue3bug-Invalid vnode type when creating vnode: null.
  16. 浏览器收藏夹(书签)导入导出
  17. 政考网:一年最多可以参加几次公务员考试?
  18. CRB开发-总体简介
  19. 「高考志愿填报」高考志愿填报数据智库项目项目总览
  20. 转载 excel生成数据地图

热门文章

  1. android新浪登录接口,新浪游戏AndroidSDK接入文档—服务端.md
  2. python银行排队系统_python-我需要基于Web的系统的消息/排队解决...
  3. python 打包文件夹_Python打包文件夹(zip/tar/
  4. python绘制直方图plt_Python:matplotlib绘制直方图
  5. java bufferedrandomaccessfile_java 读写操作大文件 BufferedReader和RandomAccessFile
  6. ionic4 返回键退出app
  7. wx:for双层循环
  8. 怎么导入sklearn包_4.5包
  9. matlab销量预测的数学模型,数学建模:酒店最优化问题.用matlab算出《酒店价格预测模型》...
  10. java字符串构造函数的应用_构造函数中的参数0需要找不到类型为'java.lang.String'的bean...