主頁 > 資料庫 > B樹索引

B樹索引

2020-09-16 03:15:32 資料庫

https://www.cnblogs.com/xqzt/p/4456746.html

 

 B-Tree索引是最常見的索引結構,默認創建的索引就是B-Tree索引,

一、B樹索引的結構

B-樹索引是基于二叉樹結構的,B-樹索引結構有3個基本組成部分:根節點、分支節點和葉子節點,其中根節點位于索引結構的最頂端,而葉子節點位于索引結構的最底端,中間為分子節點,

    葉子節點(Leaf node):包含條目直接指向表里的資料行,

    分支節點(Branch node):包含的條目指向索引里其他的分支節點或者是葉子節點,

    根節點(Branch node):一個B樹索引只有一個根節點,它實際就是位于樹的最頂端的分支節點,

可以用下圖一來描述B樹索引的結構,其中,B表示分支節點,而L表示葉子節點,

clip_image001

1.1關于分支節點塊(包括根節點塊)

1、 其所包含的索引條目都是按照順序排列的(預設是升序排列,也可以在創建索引時指定為降序排列),

2、 每個索引條目(也可以叫做每條記錄)都具有兩個欄位,第一個欄位表示當前該分支節點塊下面所鏈接的索引塊中所包含的最小鍵值;第二個欄位為四個位元組,表示所鏈接的索引塊的地址,該地址指向下面一個索引塊,

3、 在一個分支節點塊中所能容納的記錄行數由資料塊大小以及索引鍵值的長度決定,比如從上圖一可以看到,對于根節點塊來說,包含三條記錄,分別為(0 B1)、(500 B2)、(1000 B3),它們指向三個分支節點塊,其中的0、500和1000分別表示這三個分支節點塊所鏈接的鍵值的最小值,而B1、B2和B3則表示所指向的三個分支節點塊的地址,

1.2關于葉子節點

1、 B樹索引的所有葉子塊一定位于同一層上,這是由B樹的資料結構定義的,Oracle 設計的B樹索引結構保證了B 樹索引從根到葉子都有相等的分支節點,保證了B樹索引的平衡,這樣就不會因為基表的資料插入后洗掉操作造成B樹索引變得不平衡,從而影響索引的性能,因此,從根塊到達任何一個葉子塊的遍歷代價都是相同的; 索引高度是指從根塊到達葉子塊時所遍歷的資料塊的個數,通常,大多數的B樹索引的高度都是2到3,也就意味著,即使表中有上百萬條記錄,從索引中定位一個鍵字只需要2或3次I/O,索引越高,性能越差;

2、 葉子節點所包含的索引條目與分支節點一樣,都是按照順序排列的(預設是升序排列,也可以在創建索引時指定為降序排列)

3、 每個索引條目(也可以 叫做每條記錄)也具有兩個欄位,第一個欄位表示索引的鍵值,對于單列索引來說是一個值;而對于多列索引來說則是多個值組合在一起的,第二個欄位表示鍵值所對應的記錄行的ROWID,該ROWID是記錄行在表里的物理地址,ROWID 是唯一的Oracle 指標,指向該行的物理位置,使用ROWID 是Oracle 資料庫中訪問行最快的方法,參照Oracle中的rowid

4、 葉子節點其實是一個雙向鏈表,每個葉子節點包含一個指向下一個和上一個葉子點的指標,這樣在一定范圍內便利索引以搜索需要的記錄,

clip_image002

clip_image004

二、B樹索引的訪問

當oracle行程需要訪問資料檔案里的資料塊時,oracle會有兩種型別的I/O操作方式:
1) 隨機訪問,每次讀取一個資料塊(通過等待事件“db file sequential read”體現出來),
2) 順序訪問,每次讀取多個資料塊(通過等待事件“db file scattered read”體現出來),
第一種方式則是訪問索引里的資料塊,而第二種方式的I/O操作屬于全表掃描,這里順帶有一個問題,為何隨機訪問會對應到db file sequential read等待事件,而順序訪問則會對應到db file scattered read等待事件呢?這似乎反過來了,隨機訪問才應該是分散(scattered)的,而順序訪問才應該是順序(sequential)的,其實,等待事件主要根據實際獲取物理I/O塊的方式來命名的,而不是根據其在I/O子系統的邏輯方式來命名的,下面對于如何獲取索引資料塊的方式中會對此進行說明,
事實上在B樹索引雖然為一個樹狀的立體結構,但其對應到資料檔案里的排列當然還是一個平面的形式,也就是像下面這樣,
/根/分支/分支/葉子/…/葉子/分支/葉子/葉子/…/葉子/分支/葉子/葉子/…/葉子/分支/.....
因此,當oracle需要訪問某個索引塊的時候,勢必會在這個結構上跳躍的移動,
當oracle需要獲得一個索引塊時,首先從根節點開始,根據所要查找的鍵值,從而知道其所在的下一層的分支節點,然后訪問下一層的分支節點,再次同樣根據鍵值訪問再下一層的分支節點,如此這般,最終訪問到最底層的葉子節點,可以看出,其獲得物理I/O塊時,是一個接著一個,按照順序,串行進行的,在獲得最終物理塊的程序中,我們不能同時讀取多個塊,因為我們在沒有獲得當前塊的時候是不知道接下來應該訪問哪個塊的,因此,在索引上訪問資料塊時,會對應到 db file sequential read等待事件,其根源在于我們是按照順序從一個索引塊跳到另一個索引塊,從而找到最終的索引塊的,
那么對于全表掃描來說,則不存在訪問下一個塊之前需要先訪問上一個塊的情況,全表掃描時,oracle知道要訪問所有的資料塊,因此唯一的問題就是盡可能高效的訪問這些資料塊,因此,這時oracle可以采用同步的方式,分幾批,同時獲取多個資料塊,這幾批的資料塊在物理上可能是分散在表里的,因此其對應到db file scattered read等待事件,

三、DML對B樹索引的影響

3.1 INSERT

在每個INSERT操作程序中,關鍵字必須被插入在正確葉節點的位置,如果葉節點已滿,不能容納更多的關鍵字,就必須將葉節點拆分,拆分的方法有兩種:

1)如果新關鍵字值在所有舊葉節點塊的所有關鍵字中是最大的,那么所有的關鍵字將按照99:1的比例進行拆分,使得在新的葉節點塊中只存放有新關鍵字,而其他的所有關鍵字(包括所有洗掉的關鍵字)仍然保存在舊葉節點塊中,
2)如果新關鍵字值不是最大的,那么所有的關鍵字將按照50:50的比例進行拆分,這時每個葉節點塊(舊與新)中將各包含原始葉節點中的一半關鍵字,
這個拆分必須通過一個指向新葉節點的新入口向上傳送到父節點,如果父節點已滿,那么這個父節點也必須進行拆分,并且需要將這種拆分向上傳送到父節點的父節點,這時,如果這個父節點也已滿,將繼續進行這個程序,這樣,某個拆分可能最終被一直傳送到根節點,如果根節點滿了,根結點也將進行分裂,根結點在進行分裂的時候,就是樹的高度增加的時候,根節點進行分裂的方式跟其他的的節點分裂的方式相比較,在物理位置上的處理也是不同的,根節點分裂時,將原來的根結點分裂為分支節點或葉節點,保存到新的塊中,而將新的根節點資訊保存到原來的根結點塊中,這樣做的是為因為避免修改資料字典所帶來的相對較大的開銷,
注意:現在Oracle都是采用了平衡演算法,正常情況下即使索引關鍵字不斷增大,也不會產生不平衡樹,當索引關鍵字不斷增大,導致樹級別單方向增長時,Oracle會自動進行索引翻轉以維持索引的平衡,當然這種操作非常消耗資源
在索引的每一個層次之間,每一個層最左邊的節點的block頭部都有一個指向下層最左邊的塊的指標,這樣有利于fast full scan 的快速定位最左邊的葉子節點,
每個拆分程序都是要花費一定的開銷的,特別是要進行物理硬碟I/O動作,此外,在進行拆分之前,Oracle必須查找到一個空塊,用來保存這個拆分,可以用以下步驟來進行查找空塊的動作:
1) 在索引的自由串列(free-list, 又稱為空閑串列) 中查到一個空閑塊,可以通過CREATE/ALTER INDEX命令為一個索引定義多個空閑串列,索引空閑串列并不能幫助Oracle查找一個可用來存放將要被插入的新關鍵字的塊,這是因為關鍵字值不能隨機地存放在索引中可用的第一個“空閑”葉節點塊中,這個值必須經過適當的排序之后,放置在某個特定的葉節點塊中,只有在塊拆分程序中才需要使用索引的空閑串列,每個空閑串列都包含有一個關于“空”塊的鏈接串列,當為某個索引定義了多個空閑串列時,首先將從分配給行程的空間串列中掃描一個空閑塊,如果沒有找到所需要的空閑塊,將從主空閑串列中進行掃描空閑塊的動作,
2) 如果沒有找到任何空閑塊,Oracle將試圖分配另一個擴展段,如果在表空間中沒有更多的自由空間,Oracle將產生錯誤ORA-01654,
3) 如果通過上述步驟,找到了所需的空閑塊,那么這個索引的高水位標(HWM)將加大,
4) 所找到的空閑塊將用來執行拆分動作,
在創建B*樹索引時,一個需要注意的問題就是要避免在運行時進行拆分,或者,要在索引創建程序中進行拆分(“預拆分”),從而使得在進行拆分時能夠快速命中,以便避免運行時插入動作,當然,這些拆分也不僅僅局限于插入動作,在進行更新的程序中也有可能會發生拆分動作,

3.2 UPDATE

索引更新完全不同于表更新,在表更新中,資料是在資料塊內部改變的(假設資料塊中有足夠的空間來允許進行這種改變);但在索引更新中,如果有關鍵字發生改變,那么它在樹中的位置也需要發生改變,請記住,一個關鍵字在B*樹中有且只有一個位置,因此,當某個關鍵字發生改變時,關鍵字的舊表項必須被洗掉,并且需要在一個新的葉節點上創建一個新的關鍵字,舊的表項有可能永遠不會被重新使用,這是因為只有在非常特殊的情況下, Oracle才會重用關鍵字表項槽,例如,新插入的關鍵字正好是被洗掉的那個關鍵字(包括資料型別、長度等等),(這里重用的是塊,但完全插入相同的值的時候,也不一定插入在原來的被洗掉的位置,只是插入在原來的塊中,可能是該塊中的一個新位置,也正因為如此,在索引塊中保存的的記錄可能并不是根據關鍵字順序排列的,隨著update等的操作,會發生變化,)那么,這種情況發生的可能性有多大呢?許多應用程式使用一個數列來產生NUMBER關鍵字(特別是主關鍵字),除非它們使用了RECYCLE選項,否則這個數列將不會兩次產生完全相同的數,這樣,索引中被洗掉的空間一直沒有被使用,這就是在大規模洗掉與更新程序中,表大小不斷減小或至少保持不變但索引不斷加大的原因,

3.3 DELETE

當洗掉表里的一條記錄時,其對應于索引里的索引條目并不會被物理的洗掉,只是做了一個洗掉標記,當一個新的索引條目進入一個索引葉子節點的時候,oracle會檢查該葉子節點里是否存在被標記為洗掉的索引條目,如果存在,則會將所有具有洗掉標記的索引條目從該葉子節點里物理的洗掉,
當一個新的索引條目進入索引時,oracle會將當前所有被清空的葉子節點(該葉子節點中所有的索引條目都被設定為洗掉標記)識訓,從而再次成為可用索引塊,
盡管被洗掉的索引條目所占用的空間大部分情況下都能夠被重用,但仍然存在一些情況可能導致索引空間被浪費,并造成索引資料塊很多但是索引條目很少的后果,這時該索引可以認為出現碎片,而導致索引出現碎片的情況主要包括:
1、不合理的、較高的PCTFREE,很明顯,這將導致索引塊的可用空間減少,
2、索引鍵值持續增加(比如采用sequence生成序列號的鍵值),同時對索引鍵值按照順序連續洗掉,這時可能導致索引碎片的發生,因為前面我們知道,某個索引塊中洗掉了部分的索引條目,只有當有鍵值進入該索引塊時才能將空間識訓,而持續增加的索引鍵值永遠只會向插入排在前面的索引塊中,因此這種索引里的空間幾乎不能識訓,而只有其所含的索引條目全部洗掉時,該索引塊才能被重新利用,
3、經常被洗掉或更新的鍵值,以后幾乎不再會被插入時,這種情況與上面的情況類似,

四、總結

通過上面對B樹的分析,可以得出以下的應用準則:
1、避免對那些可能會產生很高的更新動作的列進行索引,
2、避免對那些經常會被洗掉的表中的多個列進行索引,若有可能,只對那些在這樣的表上會進行洗掉的主關鍵字與/或列進行索引,如果對多個列進行索引是不可避免的,那么就應該考慮根據這些列對表進行劃分,然后在每個這樣的劃分上執行TRUNCATE動作(而不是DELETE動作),TRUNCATE在與 DROP STORAGE短語一同使用時,通過重新設定高水位標來模擬洗掉表與索引以及重新創建表與索引的程序,
3、避免為那些唯一度不高的列創建B*樹索引,這樣的低選擇性將會導致樹節點塊的稠密性,從而導致由于索引“平鋪( flat)”而出現的大規模索引掃描,唯一性的程度越高,性能就越好,因為這樣能夠減少范圍掃描,甚至可能用唯一掃描來取代范圍掃描,
4)空值不存盤在單列索引中,對于復合索引的方式,只有當某個列不空時,才需要進行值的存盤,在為DML陳述句創建IS NULL或IS NOT NULL短語時,應該切記這個問題,
5)IS NULL不會導致索引掃描,而一個沒有帶任何限制的IS NOT NULL則可能會導致完全索引掃描,

參考

B+樹索引

Oracle中B-TREE索引的深入理解(原創)

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/52449.html

標籤:MySQL

上一篇:mysql引數max_binlog_cache_size設定不當引發的血案

下一篇:B樹和B+樹原理及在索引中的應用

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more