1 .B-樹定義node
B-樹是一種平衡的多路查找樹,它在文件系統中頗有用。算法
定義:一棵m 階的B-樹,或者爲空樹,或爲知足下列特性的m 叉樹:
⑴樹中每一個結點至多有m 棵子樹;
⑵若根結點不是葉子結點,則至少有兩棵子樹;數據庫
⑶除根結點以外的全部非終端結點至少有[m/2] 棵子樹;
⑷全部的非終端結點中包含如下信息數據:數據結構
(n,A0,K1,A1,K2,…,Kn,An)
其中:Ki(i=1,2,…,n)爲關鍵碼,且Ki<Ki+1,ide
Ai 爲指向子樹根結點的指針(i=0,1,…,n),且指針Ai-1 所指子樹中全部結點的關鍵碼均小於Ki (i=1,2,…,n),An 所指子樹中全部結點的關鍵碼均大於Kn.性能
n 爲關鍵碼的個數。
⑸全部的葉子結點都出如今同一層次上,而且不帶信息(能夠看做是外部結點或查找失敗的結點,實際上這些結點不存在,指向這些結點的指針爲空)。優化
即全部葉節點具備相同的深度,等於樹高度。ui
如一棵四階B-樹,其深度爲4.spa
B-樹的查找相似二叉排序樹的查找,所不一樣的是B-樹每一個結點上是多關鍵碼的有序表,在到達某個結點時,先在有序表中查找,若找到,則查找成功;不然,到按照對應的指針信息指向的子樹中去查找,當到達葉子結點時,則說明樹中沒有對應的關鍵碼。操作系統
在上圖的B-樹上查找關鍵字47的過程以下:
1)首先從更開始,根據根節點指針找到 *節點,由於 *a 節點中只有一個關鍵字,且給定值47 > 關鍵字35,則若存在必在指針A1所指的子樹內。
2)順指針找到 *c節點,該節點有兩個關鍵字(43和 78),而43 < 47 < 78,若存在比在指針A1所指的子樹中。
3)一樣,順指針找到 *g節點,在該節點找到關鍵字47,查找成功。
2. 查找算法
B- 樹查找算法分析
從查找算法中能夠看出, 在B- 樹中進行查找包含兩種基本操做:
( 1) 在B- 樹中查找結點;
( 2) 在結點中查找關鍵字。
因爲B- 樹一般存儲在磁盤上, 則前一查找操做是在磁盤上進行的, 然後一查找操做是在內存中進行的, 即在磁盤上找到指針p 所指結點後, 先將結點中的信息讀入內存, 而後再利用順序查找或折半查找查詢等於K 的關鍵字。顯然, 在磁盤上進行一次查找比在內存中進行一次查找的時間消耗多得多.
所以, 在磁盤上進行查找的次數、即待查找關鍵字所在結點在B- 樹上的層次樹, 是決定B樹查找效率的首要因素
那麼,對含有n 個關鍵碼的m 階B-樹,最壞狀況下達到多深呢?可按二叉平衡樹進行相似分析。首先,討論m 階B-數各層上的最少結點數。
由B樹定義:B樹包含n個關鍵字。所以有n+1個樹葉都在第J+1 層。
1)第一層爲根,至少一個結點,根至少有兩個孩子,所以在第二層至少有兩個結點。
2)除根和樹葉外,其它結點至少有[m/2]個孩子,所以第三層至少有2*[m/2]個結點,在第四層至少有2*[m/2]2 個結點…
3)那麼在第J+1層至少有2*[m/2]J-1個結點,而J+1層的結點爲葉子結點,因而葉子結點的個數n+1。有:
也就是說在n個關鍵字的B樹查找,從根節點到關鍵字所在的節點所涉及的節點數不超過:
3.B-樹的插入
B-樹的生成也是從空樹起,逐個插入關鍵字而得。但因爲B-樹結點中的關鍵字個數必須≥ceil(m/2)-1,所以,每次插入一個關鍵字不是在樹中添加一個葉子結點,而是首先在最低層的某個非終端結點中添加一個關鍵字,若該結點的關鍵字個數不超過m-1,則插入完成,不然要產生結點的「分裂」,
如圖(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後;
插入算法:
4. B-樹的刪除
反之,若在B-樹上刪除一個關鍵字,則首先應找到該關鍵字所在結點,並從中刪除之,若該結點爲最下層的非終端結點,且其中的關鍵字數目很多於ceil(m/2),則刪除完成,不然要進行「合併」結點的操做。倘若所刪關鍵字爲非終端結點中的Ki,則能夠指針Ai所指子樹中的最小關鍵字Y替代Ki,而後在相應的結點中刪去Y。例如,在下圖 圖4.1( a)的B-樹上刪去45,能夠*f結點中的50替代45,而後在*f結點中刪去50。
圖4.1( a)
所以,下面咱們能夠只需討論刪除最下層非終端結點中的關鍵字的情形。有下列三種可能:
(1)被刪關鍵字所在結點中的關鍵字數目不小於ceil(m/2),則只需從該結點中刪去該關鍵字Ki和相應指針Ai,樹的其它部分不變,例如,從圖 圖4.1( a)所示B-樹中刪去關鍵字12,刪除後的B-樹如圖 圖4.2( a)所示:
圖4.2( a)
(2)被刪關鍵字所在結點中的關鍵字數目等於ceil(m/2)-1,而與該結點相鄰的右兄弟(或左兄弟)結點中的關鍵字數目大於ceil(m/2)-1,則需將其兄弟結點中的最小(或最大)的關鍵字上移至雙親結點中,而將雙親結點中小於(或大於)且緊靠該上移關鍵字的關鍵字下移至被刪關鍵字所在結點中。
[例如],從圖圖4.2( a)中刪去50,需將其右兄弟結點中的61上移至*e結點中,而將*e結點中的53移至*f,從而使*f和*g中關鍵字數目均不小於ceil(m-1)-1,而雙親結點中的關鍵字數目不變,如圖圖4.2(b)所示。
圖4.2(b)
(3)被刪關鍵字所在結點和其相鄰的兄弟結點中的關鍵字數目均等於ceil(m/2)-1。假設該結點有右兄弟,且其右兄弟結點地址由雙親結點中的指針Ai所指,則在刪去關鍵字以後,它所在結點中剩餘的關鍵字和指針,加上雙親結點中的關鍵字Ki一塊兒,合併到 Ai所指兄弟結點中(若沒有右兄弟,則合併至左兄弟結點中)。
[例如],從圖4.2(b)所示 B-樹中刪去53,則應刪去*f結點,並將*f中的剩餘信息(指針「空」)和雙親*e結點中的 61一塊兒合併到右兄弟結點*g中。刪除後的樹如圖4.2(c)所示。
圖4.2(c)
若是所以使雙親結點中的關鍵字數目小於ceil(m/2)-1,則依次類推。
[例如],在 圖4.2(c)的B-樹中刪去關鍵字37以後,雙親b結點中剩餘信息(「指針c」)應和其雙親*a結點中關鍵字45一塊兒合併至右兄弟結點*e中,刪除後的B-樹如圖 4.2(d)所示。
圖 4.2(d)
B-樹主要應用在文件系統
爲了將大型數據庫文件存儲在硬盤上 以減小訪問硬盤次數爲目的 在此提出了一種平衡多路查找樹——B-樹結構 由其性能分析可知它的檢索效率是至關高的 爲了提升 B-樹性能’還有不少種B-樹的變型,力圖對B-樹進行改進
B+樹是應文件系統所需而產生的一種B-樹的變形樹。一棵m 階的B+樹和m 階的B-
樹的差別在於:
⑴有n 棵子樹的結點中含有n 個關鍵碼;
⑵全部的葉子結點中包含了所有關鍵碼的信息,及指向含有這些關鍵碼記錄的指針,且
葉子結點自己依關鍵碼的大小自小而大的順序連接。
⑶全部的非終端結點能夠當作是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵碼。
1. 索引在數據庫中的做用
在數據庫系統的使用過程中,數據的查詢是使用最頻繁的一種數據操做。
最基本的查詢算法固然是順序查找(linear search),遍歷表而後逐行匹配行值是否等於待查找的關鍵字,其時間複雜度爲O(n)。但時間複雜度爲O(n)的算法規模小的表,負載輕的數據庫,也能有好的性能。 可是數據增大的時候,時間複雜度爲O(n)的算法顯然是糟糕的,性能就很快降低了。
好在計算機科學的發展提供了不少更優秀的查找算法,例如二分查找(binary search)、二叉樹查找(binary tree search)等。若是稍微分析一下會發現,每種查找算法都只能應用於特定的數據結構之上,例如二分查找要求被檢索數據有序,而二叉樹查找只能應用於二叉查找樹上,可是數據自己的組織結構不可能徹底知足各類數據結構(例如,理論上不可能同時將兩列都按順序進行組織),因此,在數據以外,數據庫系統還維護着知足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就能夠在這些數據結構上實現高級查找算法。這種數據結構,就是索引。
索引是對數據庫表 中一個或多個列的值進行排序的結構。與在表 中搜索全部的行相比,索引用指針 指向存儲在表中指定列的數據值,而後根據指定的次序排列這些指針,有助於更快地獲取信息。一般情 況下 ,只有當常常查詢索引列中的數據時 ,才須要在表上建立索引。索引將佔用磁盤空間,而且影響數 據更新的速度。可是在多數狀況下 ,索引所帶來的數據檢索速度優點大大超過它的不足之處。
2. B+樹在數據庫索引中的應用
目前大部分數據庫系統及文件系統都採用B-Tree或其變種B+Tree做爲索引結構
1)在數據庫索引的應用
在數據庫索引的應用中,B+樹按照下列方式進行組織 :
① 葉結點的組織方式 。B+樹的查找鍵 是數據文件的主鍵 ,且索引是稠密的。也就是說 ,葉結點 中爲數據文件的第一個記錄設有一個鍵、指針對 ,該數據文件能夠按主鍵排序,也能夠不按主鍵排序 ;數據文件按主鍵排序,且 B +樹是稀疏索引 , 在葉結點中爲數據文件的每個塊設有一個鍵、指針對 ;數據文件不按鍵屬性排序 ,且該屬性是 B +樹 的查找鍵 , 葉結點中爲數據文件裏出現的每一個屬性K設有一個鍵 、 指針對 , 其中指針執行排序鍵值爲 K的 記錄中的第一個。
② 非葉結點 的組織方式。B+樹 中的非葉結點造成 了葉結點上的一個多級稀疏索引。 每一個非葉結點中至少有ceil( m/2 ) 個指針 , 至多有 m 個指針 。
2)B+樹索引的插入和刪除
①在向數據庫中插入新的數據時,同時也須要向數據庫索引中插入相應的索引鍵值 ,則須要向 B+樹 中插入新的鍵值。即上面咱們提到的B-樹插入算法。
②當從數據庫中刪除數據時,同時也須要從數據庫索引中刪除相應的索引鍵值 ,則須要從 B+樹 中刪 除該鍵值 。即B-樹刪除算法
爲何使用B-Tree(B+Tree)
二叉查找樹進化品種的紅黑樹等數據結構也能夠用來實現索引,可是文件系統及數據庫系統廣泛採用B-/+Tree做爲索引結構。
通常來講,索引自己也很大,不可能所有存儲在內存中,所以索引每每以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程當中就要產生磁盤I/O消耗,相對於內存存取,I/O存取的消耗要高几個數量級,因此評價一個數據結構做爲索引的優劣最重要的指標就是在查找過程當中磁盤I/O操做次數的漸進複雜度。換句話說,索引的結構組織要儘可能減小查找過程當中磁盤I/O的存取次數。爲何使用B-/+Tree,還跟磁盤存取原理有關。
局部性原理與磁盤預讀
因爲存儲介質的特性,磁盤自己存取就比主存慢不少,再加上機械運動耗費,磁盤的存取速度每每是主存的幾百分分之一,所以爲了提升效率,要儘可能減小磁盤I/O。爲了達到這個目的,磁盤每每不是嚴格按需讀取,而是每次都會預讀,即便只須要一個字節,磁盤也會從這個位置開始,順序向後讀取必定長度的數據放入內存。這樣作的理論依據是計算機科學中著名的局部性原理:
當一個數據被用到時,其附近的數據也一般會立刻被使用。
程序運行期間所須要的數據一般比較集中。
因爲磁盤順序讀取的效率很高(不須要尋道時間,只需不多的旋轉時間),所以對於具備局部性的程序來講,預讀能夠提升I/O效率。
預讀的長度通常爲頁(page)的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操做系統每每將主存和磁盤存儲區分割爲連續的大小相等的塊,每一個存儲塊稱爲一頁(在許多操做系統中,頁得大小一般爲4k),主存和磁盤以頁爲單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,磁盤會找到數據的起始位置並向後連續讀取一頁或幾頁載入內存中,而後異常返回,程序繼續運行。
咱們上面分析B-/+Tree檢索一次最多須要訪問節點:
h =
數據庫系統巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每一個節點只須要一次I/O就能夠徹底載入。爲了達到這個目的,在實際實現B- Tree還須要使用以下技巧:
每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,加之計算機存儲分配都是按頁對齊的,就實現了一個node只需一次I/O。
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 索引, Hash 索引, Fulltext 索引和 R-Tree 索引。咱們主要分析B-Tree 索引。
B-Tree 索引是 MySQL 數據庫中使用最爲頻繁的索引類型,除了 Archive 存儲引擎以外的其餘全部的存儲引擎都支持 B-Tree 索引。Archive 引擎直到 MySQL 5.1 才支持索引,並且只支持索引單個 AUTO_INCREMENT 列。
不只僅在 MySQL 中是如此,實際上在其餘的不少數據庫管理系統中B-Tree 索引也一樣是做爲最主要的索引類型,這主要是由於 B-Tree 索引的存儲結構在數據庫的數據檢索中有很是優異的表現。
通常來講, MySQL 中的 B-Tree 索引的物理文件大多都是以 Balance Tree 的結構來存儲的,也就是全部實際須要的數據都存放於 Tree 的 Leaf Node(葉子節點) ,並且到任何一個 Leaf Node 的最短路徑的長度都是徹底相同的,因此咱們你們都稱之爲 B-Tree 索引。固然,可能各類數據庫(或 MySQL 的各類存儲引擎)在存放本身的 B-Tree 索引的時候會對存儲結構稍做改造。如 Innodb 存儲引擎的 B-Tree 索引實際使用的存儲結構其實是 B+Tree,也就是在 B-Tree 數據結構的基礎上作了很小的改造,在每個Leaf Node 上面出了存放索引鍵的相關信息以外,還存儲了指向與該 Leaf Node 相鄰的後一個 LeafNode 的指針信息(增長了順序訪問指針),這主要是爲了加快檢索多個相鄰 Leaf Node 的效率考慮。
下面主要討論MyISAM和InnoDB兩個存儲引擎的索引實現方式:
1)主鍵索引:
MyISAM引擎使用B+Tree做爲索引結構,葉節點的data域存放的是數據記錄的地址。下圖是MyISAM主鍵索引的原理圖:
(圖myisam1)
這裏設表一共有三列,假設咱們以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的彙集索引區分。
然InnoDB也使用B+Tree做爲索引結構,但具體實現方式卻與MyISAM大相徑庭.
1)主鍵索引:
MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件自己就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以InnoDB表數據文件自己就是主索引。
(圖inndb主鍵索引)
(圖inndb主鍵索引)是InnoDB主索引(同時也是數據文件)的示意圖,能夠看到葉節點包含了完整的數據記錄。這種索引叫作彙集索引。由於InnoDB的數據文件自己要按主鍵彙集,因此InnoDB要求表必須有主鍵(MyISAM能夠沒有),若是沒有顯式指定,則MySQL系統會自動選擇一個能夠惟一標識數據記錄的列做爲主鍵,若是不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段做爲主鍵,這個字段長度爲6個字節,類型爲長整形。
2). InnoDB的輔助索引
InnoDB的全部輔助索引都引用主鍵做爲data域。例如,下圖爲定義在Col3上的一個輔助索引:
InnoDB 表是基於聚簇索引創建的。所以InnoDB 的索引能提供一種很是快速的主鍵查找性能。不過,它的輔助索引(Secondary Index, 也就是非主鍵索引)也會包含主鍵列,因此,若是主鍵定義的比較大,其餘索引也將很大。若是想在表上定義 、不少索引,則爭取儘可能把主鍵定義得小一些。InnoDB 不會壓縮索引。
文字符的ASCII碼做爲比較準則。彙集索引這種實現方式使得按主鍵的搜索十分高效,可是輔助索引搜索須要檢索兩遍索引:首先檢索輔助索引得到主鍵,而後用主鍵到主索引中檢索得到記錄。
不一樣存儲引擎的索引實現方式對於正確使用和優化索引都很是有幫助,例如知道了InnoDB的索引實現後,就很容易明白爲何不建議使用過長的字段做爲主鍵,由於全部輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如,用非單調的字段做爲主鍵在InnoDB中不是個好主意,由於InnoDB數據文件自己是一顆B+Tree,非單調的主鍵會形成在插入新記錄時數據文件爲了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段做爲主鍵則是一個很好的選擇。
InnoDB索引和MyISAM索引的區別:
一是主索引的區別,InnoDB的數據文件自己就是索引文件。而MyISAM的索引和數據是分開的。
二是輔助索引的區別:InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。而MyISAM的輔助索引和主索引沒有多大區別。
參考連接:https://blog.csdn.net/hguisu/article/details/7786014