1、B+B+树及树及MySQLMySQL数据库索引数据库索引厦门大学数据库实验室厦门大学数据库实验室罗道文罗道文2014-08-02 B树以及树以及B+树的特点以及原理树的特点以及原理 MySQL存储引擎存储引擎MyISAM和和InnoDB的的B+树索引树索引B树特性树特性1.树中每个结点最多含有树中每个结点最多含有m个孩子(个孩子(m=2););2.除根结点和叶子结点外,其它每个结点至少有除根结点和叶子结点外,其它每个结点至少有ceil(m / 2)个孩子(其中个孩子(其中ceil(x)是一个取上限的函数);是一个取上限的函数);3.若根结点不是叶子结点,则至少有若根结点不是叶子结点,则至少有2
2、个孩子(特殊情况:没有孩子的根结点,个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节点);即根结点为叶子结点,整棵树只有一个根节点);B树特性树特性4.所有叶子结点都出现在同一层,叶子节点只有关键字,没有孩子和指向孩子的指针所有叶子结点都出现在同一层,叶子节点只有关键字,没有孩子和指向孩子的指针5.每个非终端结点中包含有每个非终端结点中包含有n个关键字信息:个关键字信息: (n,P0,K1,P1,K2,P2,.,Kn,Pn)。其中:。其中: a) Ki (i=1.n)为关键字,且关键字按顺序升序排序为关键字,且关键字按顺序升序排序K(i-1) Ki。 b) Pi为指向
3、子树根的节点,且指针为指向子树根的节点,且指针P(i-1)指向子树种所有结点的关键字均小指向子树种所有结点的关键字均小于于Ki,但都大于,但都大于K(i-1)。 c) 关键字的个数关键字的个数n必须满足:必须满足: ceil(m / 2)-1= n = m-1。如下图所示:。如下图所示:来模拟下查找文件来模拟下查找文件29的过程:的过程: (1) 根据根结点指针找到文件目录的根磁盘块根据根结点指针找到文件目录的根磁盘块1,将其中的信息导入内存。【磁盘,将其中的信息导入内存。【磁盘IO操作操作1次】次】 (2) 此时内存中有两个文件名此时内存中有两个文件名17,35和三个存储其他磁盘页面地址的数
4、据。根据和三个存储其他磁盘页面地址的数据。根据算法我们发现算法我们发现172935,因此我们找到指针,因此我们找到指针p2。 (3) 根据根据p2指针,我们定位到磁盘块指针,我们定位到磁盘块3,并将其中的信息导入内存。【磁盘,并将其中的信息导入内存。【磁盘IO操作操作2次】次】 (4) 此时内存中有两个文件名此时内存中有两个文件名26,30和三个存储其他磁盘页面地址的数据。根据和三个存储其他磁盘页面地址的数据。根据算法我们发现算法我们发现262930,因此我们找到指针,因此我们找到指针p2。 (5) 根据根据p2指针,我们定位到磁盘块指针,我们定位到磁盘块8,并将其中的信息导入内存。【磁盘,并
5、将其中的信息导入内存。【磁盘IO操作操作3次】次】 (6) 此时内存中有两个文件名此时内存中有两个文件名28,29。根据算法我们查找到文件。根据算法我们查找到文件29,并定位了该,并定位了该文件内存的磁盘地址。文件内存的磁盘地址。B树插入树插入 生成树从空树开始,逐个插入关键字。首先在最底层的节点添加一个关键字,生成树从空树开始,逐个插入关键字。首先在最底层的节点添加一个关键字,如果该节点关键字个数不超过如果该节点关键字个数不超过m-1,则插入完成,否则要产生节点分裂。,则插入完成,否则要产生节点分裂。1、咱们通过一个实例来逐步讲解下。插入以下字符字母到一棵空的、咱们通过一个实例来逐步讲解下。
6、插入以下字符字母到一棵空的B 树中树中(非根结点关键字数小了(小于(非根结点关键字数小了(小于2个)就合并,大了(超过个)就合并,大了(超过4个)就分裂):个)就分裂):C N G A H E K Q M F W L T Z D P R X Y S,首先,结点空间足够,首先,结点空间足够,4个字母插个字母插入相同的结点中,如下图:入相同的结点中,如下图:2、当咱们试着插入、当咱们试着插入H时,结点发现空间不够,以致将其分裂成时,结点发现空间不够,以致将其分裂成2个结点,移动中个结点,移动中间元素间元素G上移到新的根结点中,在实现过程中,咱们把上移到新的根结点中,在实现过程中,咱们把A和和C留在
7、当前结点中,而留在当前结点中,而H和和N放置新的其右邻居结点中。如下图:放置新的其右邻居结点中。如下图:3、当咱们插入、当咱们插入E,K,Q时,不需要任何分裂操作时,不需要任何分裂操作4、插入、插入M需要一次分裂,注意需要一次分裂,注意M恰好是中间关键字元素,以致向上移到父节点中恰好是中间关键字元素,以致向上移到父节点中5、插入、插入F,W,L,T不需要任何分裂操作不需要任何分裂操作6、插入、插入Z时,最右的叶子结点空间满了,需要进行分裂操作,中间元时,最右的叶子结点空间满了,需要进行分裂操作,中间元素素T上移到父节点中,注意通过上移中间元素,树最终还是保持平衡,上移到父节点中,注意通过上移中
8、间元素,树最终还是保持平衡,分裂结果的结点存在分裂结果的结点存在2个关键字元素。个关键字元素。7、插入、插入D时,导致最左边的叶子结点被分裂,时,导致最左边的叶子结点被分裂,D恰好也是中间元素,上移恰好也是中间元素,上移到父节点中,然后字母到父节点中,然后字母P,R,X,Y陆续插入不需要任何分裂操作(别忘了,树陆续插入不需要任何分裂操作(别忘了,树中至多中至多5个孩子)。个孩子)。8.最后,当插入最后,当插入S时,含有时,含有N,P,Q,R的结点需要分裂,把中间元素的结点需要分裂,把中间元素Q上移到父节上移到父节点中,但是情况来了,父节点中空间已经满了,所以也要进行分裂,将父节点点中,但是情况
9、来了,父节点中空间已经满了,所以也要进行分裂,将父节点中的中间元素中的中间元素M上移到新形成的根结点中。这样具体插入操作的完成。上移到新形成的根结点中。这样具体插入操作的完成。B树删除树删除B树的删除操作原则:从某个节点删除一个元素之后,该节点仍然要符合树的删除操作原则:从某个节点删除一个元素之后,该节点仍然要符合B树特性,树特性,即关键字树即关键字树n满足:满足:(ceil(m/2)-1)=n =m-1,m表示最多含有表示最多含有m个孩子。个孩子。当一个节点因为删除元素而不符合上述特性时,首先是向子节点索取元素,如果子当一个节点因为删除元素而不符合上述特性时,首先是向子节点索取元素,如果子节
10、点刚好节点刚好“脱贫脱贫”,就向兄弟节点索取,如果兄弟节点也是刚好,就向兄弟节点索取,如果兄弟节点也是刚好“脱贫脱贫”,那么就,那么就与兄弟节点合并。下面通过实例讲解:与兄弟节点合并。下面通过实例讲解:操作构造的一棵操作构造的一棵5阶阶B树(树中最多含有树(树中最多含有m(m=5)个孩子,因此关键字数最小为)个孩子,因此关键字数最小为ceil(m / 2)-1=2。还是这句话,关键字数小了(小于。还是这句话,关键字数小了(小于2个)就合并,大了(超过个)就合并,大了(超过4个)个)就分裂)为例,依次删除就分裂)为例,依次删除H,T,R,E。1、首先删除元素、首先删除元素H,当然首先查找,当然首
11、先查找H,H在一个叶子结点中,且该叶子结点元素数在一个叶子结点中,且该叶子结点元素数目目3大于最小元素数目大于最小元素数目ceil(m/2)-1=2,则操作很简单,咱们只需要移动,则操作很简单,咱们只需要移动K至原来至原来H的位置,移动的位置,移动L至至K的位置(也就是结点中删除元素后面的元素向前移动)的位置(也就是结点中删除元素后面的元素向前移动)2、下一步,删除、下一步,删除T,因为因为T没有在叶子结点中,而是在中间结点中找到,咱们发现没有在叶子结点中,而是在中间结点中找到,咱们发现他的继承者他的继承者W(字母升序的下个元素字母升序的下个元素),将,将W上移到上移到T的位置,然后将原包含的
12、位置,然后将原包含W的孩的孩子结点中的子结点中的W进行删除,这里恰好删除进行删除,这里恰好删除W后,该孩子结点中元素个数大于后,该孩子结点中元素个数大于2,无需,无需进行合并操作。进行合并操作。3、下一步删除、下一步删除R,R在叶子结点中在叶子结点中,但是该结点中元素数目为但是该结点中元素数目为2,删除导致只有,删除导致只有1个元个元素,已经小于最小元素数目素,已经小于最小元素数目ceil(5/2)-1=2,而由前面我们已经知道:如果其某个相邻而由前面我们已经知道:如果其某个相邻兄弟结点中比较丰满(元素个数大于兄弟结点中比较丰满(元素个数大于ceil(5/2)-1=2),则可以向父结点借一个元
13、素,),则可以向父结点借一个元素,然后将最丰满的相邻兄弟结点中上移最后或最前一个元素到父节点中(有没有看到然后将最丰满的相邻兄弟结点中上移最后或最前一个元素到父节点中(有没有看到红黑树中左旋操作的影子红黑树中左旋操作的影子?),在这个实例中,右相邻兄弟结点中比较丰满(),在这个实例中,右相邻兄弟结点中比较丰满(3个元个元素大于素大于2),所以先向父节点借一个元素),所以先向父节点借一个元素W下移到该叶子结点中,代替原来下移到该叶子结点中,代替原来S的位置,的位置,S前移;然后前移;然后X在相邻右兄弟结点中上移到父结点中,最后在相邻右兄弟结点中删除在相邻右兄弟结点中上移到父结点中,最后在相邻右兄
14、弟结点中删除X,后面元素前移。,后面元素前移。 4、最后一步删除、最后一步删除E, 删除后会导致很多问题,因为删除后会导致很多问题,因为E所在的结点数目刚好达标,刚所在的结点数目刚好达标,刚好满足最小元素个数(好满足最小元素个数(ceil(5/2)-1=2),而相邻的兄弟结点也是同样的情况,删除一个而相邻的兄弟结点也是同样的情况,删除一个元素都不能满足条件,所以需要该节点与某相邻兄弟结点进行合并操作;首先移动父元素都不能满足条件,所以需要该节点与某相邻兄弟结点进行合并操作;首先移动父结点中的元素(该元素在两个需要合并的两个结点元素之间)下移到其子结点中,然结点中的元素(该元素在两个需要合并的两
15、个结点元素之间)下移到其子结点中,然后将这两个结点进行合并成一个结点。所以在该实例中,咱们首先将父节点中的元素后将这两个结点进行合并成一个结点。所以在该实例中,咱们首先将父节点中的元素D下移到已经删除下移到已经删除E而只有而只有F的结点中,然后将含有的结点中,然后将含有D和和F的结点和含有的结点和含有A,C的相邻兄弟的相邻兄弟结点进行合并成一个结点。结点进行合并成一个结点。5、也许你认为这样删除操作已经结束了,其实不然,在看看上图,对于这种特殊、也许你认为这样删除操作已经结束了,其实不然,在看看上图,对于这种特殊情况,你立即会发现父节点只包含一个元素情况,你立即会发现父节点只包含一个元素G,没
16、达标(因为非根节点包括叶子结,没达标(因为非根节点包括叶子结点的关键字数点的关键字数n必须满足于必须满足于2=n=4,而此处的,而此处的n=1),这是不能够接受的。如果),这是不能够接受的。如果这个问题结点的相邻兄弟比较丰满,则可以向父结点借一个元素。假设这时右兄弟这个问题结点的相邻兄弟比较丰满,则可以向父结点借一个元素。假设这时右兄弟结点(含有结点(含有Q,X)有一个以上的元素()有一个以上的元素(Q右边还有元素),然后咱们将右边还有元素),然后咱们将M下移到元下移到元素很少的子结点中,将素很少的子结点中,将Q上移到上移到M的位置,这时,的位置,这时,Q的左子树将变成的左子树将变成M的右子树
17、,也的右子树,也就是含有就是含有N,P结点被依附在结点被依附在M的右指针上。所以在这个实例中,咱们没有办法去借的右指针上。所以在这个实例中,咱们没有办法去借一个元素,只能与兄弟结点进行合并成一个结点,而根结点中的唯一元素一个元素,只能与兄弟结点进行合并成一个结点,而根结点中的唯一元素M下移到下移到子结点,这样,树的高度减少一层。子结点,这样,树的高度减少一层。B+树特性树特性一颗一颗m阶的阶的B+树和树和m阶的阶的B树的差异在于:树的差异在于:1.有有n棵子树的结点中含有棵子树的结点中含有n个关键字;个关键字; (而而B树是树是n棵子树有棵子树有n-1个关键字个关键字)2.所有的叶子结点中包含
18、了全部关键字的信息,及指向含有这些关键字记录的所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。指针,且叶子结点本身依关键字的大小自小而大的顺序链接。(而而B树的叶子节树的叶子节点并没有包括全部需要查找的信息点并没有包括全部需要查找的信息)3.所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。(或最小)关键字。 (而而B 树的非终节点也包含需要查找的有效信息树的非终节点也包含需要查找的有效信息)B树:树:B树和树和B+树为何适
19、存储索引?树为何适存储索引?一般来说,索引本身也很大,不可能全部存储在内存中,一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘话,索引查找过程中就要产生磁盘I/O消耗,相对于内存消耗,相对于内存存取,存取,I/O存取的消耗要高几个数量级,所以评价一个数存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中据结构作为索引的优劣最重要的指标就是在查找过程中磁盘磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构操作次数的渐进复杂度。换句话
20、说,索引的结构组织要尽量减少查找过程中磁盘组织要尽量减少查找过程中磁盘I/O的存取次数。的存取次数。B-Tree中一次检索最多需要中一次检索最多需要h-1次次I/O(根节点常驻内(根节点常驻内存),渐进复杂度为存),渐进复杂度为O(h)=O(logmN)。一般实际)。一般实际应用中,应用中,m是非常大的数字,通常超过是非常大的数字,通常超过100,因此,因此h非常非常小(通常不超过小(通常不超过3)。)。B+Tree:非叶子节点只存:非叶子节点只存key,大大滴减少了非叶子节点的大小,那么,大大滴减少了非叶子节点的大小,那么每个节点就可以存放更多的记录,树更矮了,每个节点就可以存放更多的记录,
21、树更矮了,I/O操作更少了。所以操作更少了。所以B+Tree拥有更好的性能。拥有更好的性能。MySQL数据库存储引擎:数据库存储引擎:MyISAM和和InnoDB MyISAM和和InnoDB引擎都使用引擎都使用B+Tree作为索引结构。作为索引结构。1.MyISAM索引实现:索引实现:(1).主键索引主键索引:MyISAM引擎使用引擎使用B+Tree作为索引结构,叶节点的作为索引结构,叶节点的data域存放的是域存放的是数据记录的地址。下图是数据记录的地址。下图是MyISAM主键索引的原理图:主键索引的原理图:2)辅助索引()辅助索引(Secondary key)在在MyISAM中,主索引和
22、辅助索引(中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只)在结构上没有任何区别,只是主索引要求是主索引要求key是唯一的,而辅助索引的是唯一的,而辅助索引的key可以重复。如果我们在可以重复。如果我们在Col2上建立上建立一个辅助索引,则此索引的结构如下图所示:一个辅助索引,则此索引的结构如下图所示:InnoDB索引实现索引实现1)主键索引:)主键索引:MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按中,表数据文件本身就是按B+Tree组织的一
23、个索引结构,这棵树的叶节点组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的域保存了完整的数据记录。这个索引的key是数据表的主键,因此是数据表的主键,因此InnoDB表表数据文件本身就是主索引。数据文件本身就是主索引。如图是如图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚的数据文件本身要按主键聚集,所以集,所以InnoDB要求表必须有主键。要求表必须有主键。2). I
24、nnoDB的辅助索引的辅助索引 InnoDB的所有辅助索引都引用主键作为的所有辅助索引都引用主键作为data域。例如,下图为定义在域。例如,下图为定义在Col3上上的一个辅助索引:的一个辅助索引: InnoDB 表是基于聚簇索引建立的。因此表是基于聚簇索引建立的。因此InnoDB 的索引能提供一种非常快速的主的索引能提供一种非常快速的主键查找性能。不过,它的辅助索引(键查找性能。不过,它的辅助索引(Secondary Index, 也就是非主键索引)也会也就是非主键索引)也会包含主键列,所以,如果主键定义的比较大,其他索引也将很大。如果想在表上定包含主键列,所以,如果主键定义的比较大,其他索引
25、也将很大。如果想在表上定义义 、很多索引,则争取尽量把主键定义得小一些。、很多索引,则争取尽量把主键定义得小一些。InnoDB 不会压缩索引。不会压缩索引。一是主索引的区别,一是主索引的区别,InnoDB的数据文件本身就是索引文件。而的数据文件本身就是索引文件。而MyISAM的索的索引和数据是分开的。引和数据是分开的。二是辅助索引的区别:二是辅助索引的区别:InnoDB的辅助索引的辅助索引data域存储相应记录主键的值而不域存储相应记录主键的值而不是地址。而是地址。而MyISAM的辅助索引和主索引没有多大区别。的辅助索引和主索引没有多大区别。InnoDB索引和索引和MyISAM索引的区索引的区别:别:Thanks for listening