MySql中B+索引和ISAM索引介绍

来源:互联网 发布:2016年日本进出口数据 编辑:程序博客网 时间:2024/06/05 15:47

名词:索引顺序存取方法ISAM—Indexed Sequential Access Method

索引顺序存取方法(ISAM, Indexed Sequential Access Method)最初是IBM公司发展起来的一个文件系统,可以连续地(按照他们进入的顺序)或者任意地(根据索引)记录任何访问。每个索引定义了一次不同排列的记录。现在这个概念用在许多场合:

  • 特指IBM公司的ISAM产品
  • 数据库系统中提供用户接口从数据文件中检索数据。
  • 通常指,数据库的索引,这种索引被大多数数据库所采用,包括关系数据库或其它。

在ISAM系统,数据组织成有固定长度的记录,按顺序存储的。

-------------------------------------------------------------------------

首先介绍一些概念

索引是在磁盘上组织数据记录的一种数据结构,它用于优化某类数据检索的操作。索引使得我们能够有效地检索满足索引的搜索码字段上的搜索条件的那些记录。可以在一个给定的数据记录集合上创建多个索引,每一个索引都有不同的搜索码,以支持那些不能被文件组织有效支持的搜索操作。

我们使用术语数据项来指代存储在索引文件中的记录。搜索码值为k的数据项记为k*,包含有足够的信息以定位(一个或多个)搜索码值为k的数据记录。我们可以有效地搜索一个索引来找到想要的数据项,然后使用这些数据项来获得数据记录。(数据项 数据记录)

基于树的索引——树型的数据结构

构成形式:数据项按照搜索码值进行排列,并且维护一个层次化的搜索数据结构,以便将搜索定向到数据项所属的页面。

图中显示了一个雇员记录文件,按照搜索码“年龄”组织成一个树结构的索引。该图中的每一个节点(例如,节点A,B,L1,L2)是一个物理页,并且检索一次节点就要涉及一次I/O。树的最下层,就是叶子层,包含数据项。在我们的示例中,这些数据就是雇员记录。

这种结构使得可以用搜索码值有效地定为指定范围内德所有数据项。所有的搜索都开始与最顶端的节点,称其为根节点,然后非叶子层的节点的内容将搜索定位到正确的叶子页上。非叶子页包含按照搜索码值分开的节点指针。码值k左边的节点指针指向一个只含有小于k的数据项的子树。码值k右边的节点指针指向一个只含有大于或等于k的数据项的子树。

 

现在考虑两种基于树型组织的索引结构:ISAM和B+树。

ISAM树是一个静态索引结构,它在文件不频繁修改的情况下非常有效,但它不适合频繁增长和缩小的数据文件。

B+树是一个能适应文件变化的动态结构。因为它能有效地适应变化,支持等值和范围查询。

在ISAM和B+树结构中,叶子页包含数据项。为了方便起见,将把拥有搜索码值k的数据项表示为k*。非叶子页包含索引项,其形式为<搜索码值,页标识符>,它用于直接搜索需要的数据项(存储在叶子页中)。

树索引介绍

索引页的格式

 

我们称形如<码,指针>的对为索引项。请注意每一个索引页中所含的指针都要比码的个数多一个,因为每一个码都作为其左右指针所指页面内容的分隔符。

一个简单的索引文件数据结构如图所示

 

索引顺序存取方法:

索引顺序存取方法(ISAM)的数据结构如图所示。



数据页   索引页    溢出页

ISAM索引的数据项存放在树的叶子页和串链到叶子页的其他溢出页中。ISAM结构完全是静态的(除了溢出页,但它们只有很少),并且便于底层优化。

每一个树节点是一个磁盘页,并且所有的数据存放在叶子页。当创建文件时,顺序分配所有叶子页并在搜索码值上排序,然后再分配非叶子级的页。如果随后对文件有一些插入操作,以至于多个项被插入到一个叶子页,使之超出一页,则需要分配另外的页,因为索引结构是静态的。这些另外的页是从溢出区分配的。页的分配如图所示

插入、删除和搜索这些节本操作都可以直接出来。对于等值搜索,可以从根节点开始,通过把给定记录的搜索字段的值与节点中的码值相比较,确定沿哪一个子树继续搜索(搜索算法与B+树相同)。对于范围搜索,数据(或叶子)级的开始点的确定与上述相似,接着是顺序搜索数据页。对于插入和删除操作,通过搜索来确定合适的页,然后插入或删除记录,必要时增加溢出页。

下面是一个例子。


设想如图所示的树,所有的搜索从根开始。例如,为了定位码值为27的记录,因为27<40,所以,从根开始沿着左指针继续。接着沿着中间指针继续,因为20≤27<33。对于范围搜索,可以像等值搜索那样找到第一个满足条件的数据项,然后顺序搜索主叶子页(必要时页通过沿着来自主页的指针去搜索溢出页)。假设主叶子页是顺序分配的,这一假设是合理的,因为页的数目在创建树时是已知的,并且在随后的插入和删除中也不改变,所以,不需要“指向下一叶子页的” 指针。

假设每一叶子页包含两个数据项。如果现在插入码值为23的记录,项23*属于第二个数据页,但该页已经包含20*和27*两项,已经没有空间了。在这种情况下,将增加一个溢出页,并把23*放入该溢出页。溢出页链很容易维护。例如插入48*,41*和42*将产生两页的溢出链。图1中的树经过所有这些插入后的状态如图2所示。

溢出页与加锁考虑

值得注意的是,一旦ISAM文件被创建,插入和删除只影响叶子页的内容。这样设计的结果是,如果大量插入操作作用于同一叶子,则产生很长的溢出页链。这些链非常影响搜索记录的时间,因为当搜索达到这个叶子时,溢出链页需要被搜索(尽管溢出链的数据能够保持排列顺序,但为了加快插入操作,它常常不保持顺序)。为了解决这个问题,树在开始创建时为每一页保留了20%的空闲空间。但是,一旦空闲空间被插入的记录填满,除非再次通过删除而获得释放的空间,否则就只有通过完全重组文件才能消除溢出链。

只有叶子页被修改对于并发访问也有好处。当一页被访问时,会被申请者锁定,以保证它不被该页的其他用户并发修改。为了修改这一页,必须以“互斥”的方式锁定该页。加锁可能导致用户(准确地说是事务)进入等待存取该页的队列。队列是最大的性能瓶颈,尤其是当大量存取索引结构中接近根的页时。ISAM结构中,既然已经知道索引级的页从不修改,所以可以安全地忽略加锁步骤。不对索引级页加锁时ISAM优于B+树动态结构的一个重要优点。当数据分布和大小相对稳定而使得溢出链很少时,ISAM将优于B+树。

B+树:一种动态索引结构

像ISAM索引这样的静态结构存在如下问题:随着文件的增长将产生很长的溢出链,从而导致很差的性能。这个问题促进了更灵活的、能随时插入和删除而调整动态结构的发展。被广泛使用的B+树是一个平衡树,它的内节点用于指导搜索,叶子节点包含数据项。由于树结构需要动态增长和缩小,所以就不能像ISAM那样(ISAM的主叶子页的集合是静态的)简单地顺序分配叶子页。为了有效地搜索所有的叶子页,就不得不用指针把叶子页链起来。通过双向链表,可以很容易地从两个方向遍历叶子页序列。

B+树的主要特征

树上的操作(插入,删除)能保持的平衡

如果能实现删除算法,则除根节点外,每一个节点都将保证最小50%的占有率【这里不是很理解什么是占有率】。但是,删除的实现通常是简单的定位数据项,并移走它,而不为保证50%的占有率而调整它,这主要是因为文件在典型情况下是增长而不是缩小。

搜索记录需要从根开始遍历到合适的叶子。从到叶子的路径长度称为树的高度,因为是平衡树,所以从根到任意叶子的长度都是相同的(平衡树,高度相差不超过1)。

下面将研究每个节点包含m个项的B+树,其中d≤m≤2d,d是B+树的一个参数,称为数的秩,它是树节点的度量。根节点是唯一不需要满足项数目要求的例外节点,它只需满足1≤m≤2d。

B+树节点格式:

B+树的节点的格式与ISAM的相同。有m个索引项的非叶子节点包含m+1个指向孩子的指针。指针Pi为指向所有码值K满足Ki≤K≤Ki+1的子树。而作为一个特殊情况,P0是指向所有码值小于K1的子树,Pm指向所有码值大于或等于Km的子树。对于叶子节点,项通常表示为k*。像ISAM一样,叶子节点(并且只有叶子节点)包含数据项。叶子页以双向链表的形式连接起来。所以,叶子形成一个序列,它能有效地解决范围查询的问题。

B+树与ISAM对比

如果存放记录的文件需要频繁地修改,并且是顺序存取的操作,维护数据记录作为数据项的B+树索引总是比维护排序文件有优势。通过付出存储索引项的空间的开销,可以获得所有排序文件的优点和有效地插入和删除效率。B+树典型地保持67%的空间占有率。B+树也由于其插入处理不需要溢出链而优于ISAM索引。但是,如果数据集大小和分布保持相对稳定,溢出链可能不是主要问题。在这种情况下,有两个优点支持ISAM:顺序分配叶子页(使大范围的扫描比B+树有效,因为B+树的页在长时间后可能在磁盘上不再有顺序,当不再有顺序之后,大范围的扫描,就会增加磁盘io)和比B+树低的加锁开销(ISAM索引节点不需要加锁)。在一般情况下,B+树比ISAM优势更明显。 

--------------------------------------------------------------------------

P31实际的B+树

补充:

a、检索一个节点就要涉及一次I/O,因此在搜索中出现的磁盘I/O数就等于从根节点到叶节点的路径长加上满足条件的数据项的叶子页的个数(实际上,根通常是在缓冲池中,因为他要被频繁地访问,所以对一个高度为3的树,其实只需要3次I/O)。

b、非叶结点的平均孩子数称为数的扇出。

P321、码压缩

B+树的高度依赖于数据项的数目和索引的大小。索引项的大小决定一页能存放索引项的数目(成反比,每个索引越大,每页存放的索引数目就越少),即树的扇出数。既然树的高度与㏒扇出(数据项数)成正比,所以,使B+树的扇出数最大、高度最小是很重要的策略。

索引项包含一个搜索码值和页的指针,所以其大小要依赖于搜索码值的大小。如果搜索码值非常大(例如一个很长的名字),一页(这里为什么一定是要放在一页里面呢?是为了减小io。如果同一个数据分散在两个页里面,那么取同一个数据就要取出两个数据页,也就是要两次io了。浪费了一次。)就不能放很多索引项,导致扇出数很小,树的高度很大。

P33另一方面,索引项中的搜索码值仅仅用于知道搜索到达合适的叶子。如果需要对给定的搜索码值的数据项进行定位,只要把这个搜索码值与(从根到期望的叶子的路径上的)索引项的搜索码值相比较。在与索引级节点进行比较时,要找到包含索引码值k1和k2,并且期望码值k刚好落在k1和k2之间的两个索引项。为了完成这个过程,不需要在索引项中存储完整的搜索码值。

例如,假设在一个节点内有两个邻近的索引项,它们的索引码值是David Smith和Devarakonda……。为了区别这两个值,只需要存储简短的形式Da和De就够了。

P34rid上插入和删除的影响

如果叶子页包含数据记录,即B+树是聚簇索引,那么诸如分裂、合并和重分布等操作将改变rid。回忆一下,rid的典型表达形式是(物理)页号和槽号的结合。这种模式在适当的页格式下允许记录在页内移动,但不能跨页移动,这对分裂操作也是一样的。所以,除非rid的选择独立于页号,否则,聚簇索引B+树的分裂或合并操作可能需要对同一数据上的其他索引进行补偿修改。

对于任何动态聚簇索引,不管它是基于树或基于哈希的,都有类似的问题。当然,对于非聚簇索引则不会产生这个问题,因为只有索引项被移动。