B-樹和B+樹的應用:數據搜索和數據庫索引
B-樹
1 .B-樹定義
B-樹是一種平衡的多路查找樹,它在文件系統中很有用。
定義:一棵m 階的B-樹,或者為空樹,或為滿足下列特性的m 叉樹:
⑴樹中每個結點至多有m 棵子樹;
⑵若根結點不是葉子結點,則至少有兩棵子樹;
⑶除根結點之外的所有非終端結點至少有[m/2] 棵子樹;
⑷所有的非終端結點中包含以下信息數據:
其中:Ki(i=1,2,…,n)為關鍵碼,且Ki
⑸所有的葉子結點都出現在同一層次上,并且不帶信息(可以看作是外部結點或查找失敗的結點,實際上這些結點不存在,指向這些結點的指針為空)。
B-樹的查找類似二叉排序樹的查找,所不同的是B-樹每個結點上是多關鍵碼的有序表,在到達某個結點時,先在有序表中查找,若找到,則查找成功;否則,到按照對應的指針信息指向的子樹中去查找,當到達葉子結點時,則說明樹中沒有對應的關鍵碼。
在上圖的B-樹上查找關鍵字47的過程如下:
1)首先從更開始,根據根節點指針找到 *節點,因為 *a 節點中只有一個關鍵字,且給定值47 > 關鍵字35,則若存在必在指針A1所指的子樹內。
2)順指針找到 *c節點,該節點有兩個關鍵字(43和 78),而43 < 47 < 78,若存在比在指針A1所指的子樹中。
3)同樣,順指針找到 *g節點,在該節點找到關鍵字47,查找成功。
2. 查找算法
- typedef
int KeyType ; - #define
m 5 - typedef
struct Node{ -
int keynum; -
struct Node *parent; -
KeyType key[m+1]; -
struct Node *ptr[m+1]; -
Record *recptr[m+1]; - }NodeType;
-
- typedef
struct{ -
NodeType *pt; -
int i; -
int tag; - }Result;
-
- Result
SearchBTree(NodeType *t,KeyType kx) - {
-
-
-
-
p=t;q=NULL;found=FALSE;i=0; -
while(p&&!found) -
{ n=p->keynum;i=Search(p,kx); -
if(i>0&&p->key[i]= =kx) found=TRUE; -
else {q=p;p=p->ptr[i];} -
} -
if(found) return (p,i,1); -
else return (q,i,0); - }
B- 樹查找算法分析
從查找算法中可以看出, 在B- 樹中進行查找包含兩種基本操作:
3.B-樹的插入
如圖(a) 為3階的B-樹(圖中略去F結點(即葉子結點)),假設需依次插入關鍵字30,26,85。
1) 首先通過查找確定插入的位置。由根*a 起進行查找,確定30應插入的在*d 節點中。由于*d 中關鍵字數目不超過2(即m-1),故第一個關鍵字插入完成:如(b)
2) 同樣,通過查找確定關鍵字26亦應插入 *d. 由于*d節點關鍵字數目超過2,此時需要將 *d分裂成兩個節點,關鍵字26及其前、后兩個指針仍保留在 *d 節點中,而關鍵字37 及其前、后兩個指針存儲到新的產生的節點 *d` 中。同時將關鍵字30 和指示節點 *d `的指針插入到其雙親的節點中。由于 *b節點中的關鍵字數目沒有超過2,則插入完成.如(c)(d)
3) (e) -(g) 為插入85后;
插入算法:
- int
InserBTree(NodeType int**t,KeyType kx,NodeType *q, i){ -
-
-
x=kx;ap=NULL;finished=FALSE; -
while(q&&!finished) -
{ -
Insert(q,i,x,ap); -
if(q->keynum finished=TRUE; -
else -
{ -
s=m/2;split(q,ap);x=q->key[s]; -
-
q=q->parent; -
if(q) i=Search(q,kx); -
} -
} -
if(!finished) -
NewRoot(t,q,x,ap); - }
因此,下面我們可以只需討論刪除最下層非終端結點中的關鍵字的情形。有下列三種可能:
[例如],從圖圖4.2( a)中刪去50,需將其右兄弟結點中的61上移至*e結點中,而將*e結點中的53移至*f,從而使*f和*g中關鍵字數目均不小于ceil(m-1)-1,而雙親結點中的關鍵字數目不變,如圖圖4.2(b)所示。
[例如],從圖4.2(b)所示 B-樹中刪去53,則應刪去*f結點,并將*f中的剩余信息(指針“空”)和雙親*e結點中的 61一起合并到右兄弟結點*g中。刪除后的樹如圖4.2(c)所示。
[例如],在
B-樹主要應用在文件系統
為了將大型數據庫文件存儲在硬盤上 以減少訪問硬盤次數為目的 在此提出了一種平衡多路查找樹——B-樹結構 由其性能分析可知它的檢索效率是相當高的 為了提高
B+樹
樹的差異在于:
⑴有n 棵子樹的結點中含有n 個關鍵碼;
⑵所有的葉子結點中包含了全部關鍵碼的信息,及指向含有這些關鍵碼記錄的指針,且
葉子結點本身依關鍵碼的大小自小而大的順序鏈接。
⑶所有的非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵碼。

樹,不管查找成功與否,每次查找都是走了一條從根到葉子結點的路徑。
B+樹在數據庫中的應用
1.
2. B+樹在數據庫索引中的應用
目前大部分數據庫系統及文件系統都采用B-Tree或其變種B+Tree作為索引結構
1)在數據庫索引的應用
在數據庫索引的應用中,B+樹按照下列方式進行組織
①
②
2)B+樹索引的插入和刪除
①在向數據庫中插入新的數據時,同時也需要向數據庫索引中插入相應的索引鍵值 ,則需要向 B+樹
②當從數據庫中刪除數據時,同時也需要從數據庫索引中刪除相應的索引鍵值 ,則需要從 B+樹 中刪
為什么使用B-Tree(B+Tree)
一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程中就要產生磁盤I/O消耗,相 對于內存存取,I/O存取的消耗要高幾個數量級,所以評價一個數據結構作為索引的優劣最重要的指標就是在查找過程中磁盤I/O操作次數的漸進復雜度。換句 話說,索引的結構組織要盡量減少查找過程中磁盤I/O的存取次數。為什么使用B-/+Tree,還跟磁盤存取原理有關。
由于存儲介質的特性,磁盤本身存取就比主存慢很多,再加上機械運動耗費,磁盤的存取速度往往是主存的幾百分分之一,因此為了提高效率,要盡量減少磁盤 I/O。為了達到這個目的,磁盤往往不是嚴格按需讀取,而是每次都會預讀,即使只需要一個字節,磁盤也會從這個位置開始,順序向后讀取一定長度的數據放入 內存。這樣做的理論依據是計算機科學中著名的局部性原理:
當一個數據被用到時,其附近的數據也通常會馬上被使用。
程序運行期間所需要的數據通常比較集中。
由于磁盤順序讀取的效率很高(不需要尋道時間,只需很少的旋轉時間),因此對于具有局部性的程序來說,預讀可以提高I/O效率。
預讀的長度一般為頁(page)的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操作系統往往將主存和磁盤存儲區分割為連續的大小相等的塊,每個存儲 塊稱為一頁(在許多操作系統中,頁得大小通常為4k),主存和磁盤以頁為單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會 向磁盤發出讀盤信號,磁盤會找到數據的起始位置并向后連續讀取一頁或幾頁載入內存中,然后異常返回,程序繼續運行。
B-Tree中一次檢索最多需要h-1次I/O(根節點常駐內存),漸進復雜度為O(h)=O(logmN)。一般實際應用中,m是非常大的數字,通常超過100,因此h非常小(通常不超過3)。
綜上所述,用B-Tree作為索引結構效率是非常高的。
而紅黑樹這種結構,h明顯要深的多。由于邏輯上很近的節點(父子)物理上可能很遠,無法利用局部性,所以紅黑樹的I/O漸進復雜度也為O(h),效率明顯比B-Tree差很多。
MySQL的B-Tree索引(技術上說B+Tree)
下面主要討論MyISAM和InnoDB兩個存儲引擎的索引實現方式:
1. MyISAM索引實現:
1)主鍵索引:
MyISAM引擎使用B+Tree作為索引結構,葉節點的data域存放的是數據記錄的地址。下圖是MyISAM主鍵索引的原理圖:
這里設表一共有三列,假設我們以Col1為主鍵,圖myisam1是一個MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件僅僅保存數據記錄的地址。
2)輔助索引(Secondary key)
在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重復。如果我們在Col2上建立一個輔助索引,則此索引的結構如下圖所示:
同樣也是一顆B+Tree,data域保存數據記錄的地址。因此,MyISAM中索引檢索的算法為首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然后以data域的值為地址,讀取相應數據記錄。
MyISAM的索引方式也叫做“非聚集”的,之所以這么稱呼是為了與InnoDB的聚集索引區分。
2. InnoDB索引實現
然InnoDB也使用B+Tree作為索引結構,但具體實現方式卻與MyISAM截然不同.
1)主鍵索引:
(圖inndb主鍵索引)是InnoDB主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄。這種索引叫做聚集索引。 因為InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選 擇一個可以唯一標識數據記錄的列作為主鍵,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含字段作為主鍵,這個字段長度為6個字節,類型 為長整形。
2). InnoDB的輔助索引
一是主索引的區別,InnoDB的數據文件本身就是索引文件。而MyISAM的索引和數據是分開的。
二是輔助索引的區別:InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。而MyISAM的輔助索引和主索引沒有多大區別。