SQL Server索引进阶第十篇:索引的内部结构
??索引設計是數據庫設計中比較重要的一個環節,對數據庫的性能其中至關重要的作用,但是索引的設計卻又不是那么容易的事情,性能也不是那么輕易就獲取到的,很多的技術人員因為不恰當的創建索引,最后使得其效果適得其反,可以說“成也索引,敗也索引”。????????
????本系列文章來自Stairway to SQL Server Indexes,然后經過我們團隊的理解和整理發布在agilesharp,希望對廣大的技術朋友在如何使用索引上有所幫助????
????
系列文章索目錄:
SQL Server索引進階第一篇:索引介紹
SQL Server索引進階第二篇:深入非聚集索引
SQL Server索引進階第三篇:聚集索引
SQL Server索引進階第四篇:頁和區
SQL Server索引進階第五篇:索引包含列
SQL Server索引進階第六篇:書簽
SQL Server索引進階第七篇:過濾的索引
SQL Server索引進階第八篇:唯一索引
SQL Server索引進階第九篇:解讀執行計劃
SQL Server索引進階第十篇:索引的內部結構
SQL Server索引進階第十一篇:索引碎片分析與解決(上)
SQL Server索引進階第十一篇:索引碎片分析與解決(中)-碎片發生原理深度剖析
SQL Server索引進階第十二篇:索引的創建,修改和刪除
SQL Server索引進階第十三篇:Insert,Update,Delete語句
SQL Server索引進階第十四篇:索引統計
SQL Server索引進階第十五篇:索引的最佳實踐
????在前一系列文章中我們著重講述了有關索引各種比較虛的概念,比如索引可以做什么,索引的邏輯結構,接下來是時候來講述比較實在的東西了,也就是索引的物理結構。理解索引的內部結構對于整體的理解索引是至關重要的,只有理解了索引的內部結構以及SQL Server是如何維護索引的,你才能理解數據插入,刪除,更新,索引的創建、修改、刪除所帶來的成本。
葉子層級和非葉子層級????
????所有的索引都是由葉子層級和非葉子層級組成的。前面的文章主要關注了索引的葉子層級。對于聚集索引來說,葉子節點就是索引本身,每一個葉子節點所包含的條目其實就是表中的行。對于非聚集索引來說,葉子節點每一個葉子包含的一行就是一個條目。每一個條目由索引鍵列,可選的包含列以及書簽構成,而書簽又由聚集索引鍵或RID構成。????????????????無論索引中條目是來自表行(聚集索引葉子節點),指向表行(非聚集索引葉子節點)或是指向低層級的節點(非葉子節點),索引條目都可以被稱為索引行。??
???? 非葉子節點是葉子節點層級的上層,SQL Server使用非葉子節點來:
- ????使得索引按照索引鍵聚集有序
- ????根據索引鍵快速找到葉子節點
????在本系列第一篇文章中,我們使用電話本的類比來解釋為什么索引能夠帶來性能的提升。用戶知道電話本是按照姓氏進行排序的,因此如果需要找”Meyer, Helen”根據首字母M知道這個人大概在電話本的中間位置,用戶直接翻開大約一半電話本開始查找。但對于SQL Server來說,可并不知道什么是按字母表排序,也不知道哪一些頁是所謂的中間頁,除非把索引中的所有頁掃描一遍。為了不用掃描所有的頁來找到所需條目,SQL Server為在葉子節點之上增加了額外的頁。
非葉子層級??
????這些額外的頁也就是所謂的非葉子節點,或被稱為索引的節點層級,是建立在葉子層級之上的層級。非葉子層級的作用是使得SQL Server對于特定的索引進行查找時,不僅有了統一的入口頁,并且不再需要掃描所有的頁。??????????
???? 在索引中的所有頁,無論哪個層級,都包含索引條目。正如文章中不斷重復說的,對于聚集索引來說,葉子節點的條目包含實際的行,所以如果一個表中包含了10億行,那么葉子節點包含了10億個條目。????在葉子節點之上的層級,也就是非葉子節點的最底層,非葉子節點的最底層每一個索引條目都指向葉子節點。如果說表中每一頁能容納100個條目,那么剛才的十億行需要1000000000/100=1000萬個頁,與之對應的是,那么最底層的非葉子節點就包含了1000萬的條目,也就是分布在1000萬/100=10萬個頁中。(譯者注:原作者這里沒說全,通常來說非葉子節點只包含索引鍵,因此每個條目的大小會遠遠小于葉子節點的條目大小,因此每頁可以容納更多的行,所以這里非葉子節點應該遠遠小于10W個頁,后面的段落我們先不管這個,還是按照10W個頁算)。??
???? 再上一層的非葉子節點包含了指向這10萬個頁的條目,也就是10萬個條目,這10W個索引條目分布在10萬/1000=1000頁中。根據這個規律,我們知道再上一層包含10個頁,直至最上層的節點只有一個頁了。
??
???? 索引中最上層的節點被稱為根頁。剩下的除了根頁和葉子之外的層級就是所謂的中間層級。層級的編號是從葉子節點以0開始向上增長的,因此中間層級是以1開始的。????非葉子節點僅僅包含索引鍵,對于擁有包含列的索引來說,包含列僅僅存在于葉子節點。
????
????索引中的頁,除了根頁之外,都含有兩個額外的指針,分別指向按照索引順序當前頁之前和之后的頁。這種雙向鏈表結構使得SQL Server在索引掃描的時候更加有效。
一個簡單的例子 ??
????讓我們通過一個簡單的圖示來真正理解索引的內部結構吧,如下圖1所示。我們在Personnel.Employee表上創建了一個非聚集索引,代碼如下:
圖例注釋:???? 指向頁的指針包含了文件號和頁號。比如說5:4567指向的就是第5個文件的4567個頁。
9/9/2012 11:19:21 AM
圖1.索引的豎切圖????
????值得說明的是,上面的圖只是一個樣子,正常的情況下一個頁中會包含遠多于上面例子的行,并且頁也會遠遠多于上面的例子。????
????實際在頁中索引條目并不是有序的,而是靠偏移指針進行定位的,這個頁尾的偏移表是有序的。????
????很多情況下,頁中并不像上面圖中所展現的那樣,頁之間物理上是連續的,但它們之間邏輯上是連續的,邏輯和物理上的差異被稱之為碎片。??
???? 正如我們之前所說,每一個索引可以包含不止一層的中間頁。????
????繼續使用我們之前電話本的類比。比如你查找名為Helen Meyer的聯系人,打開電話本找到第一頁,對于在區間 “Fernandez, Zelda”和 “Olsen, Karl”之間的名字,去看頁5:431.然后你找到431頁,這頁告訴你對于Kumar, Kevin”和“Nara, Alison”之間的名字,去找頁5:2006。然后你找到5:2006就找到了你所需的聯系人。
索引深度????
????索引的根頁以及相關信息是存在系統表中的。每當SQL Server進行頁查找時,SQL Server都會從根頁開始查找,經過中間節點,直到找到葉子節點,然后從葉子中找到需要的索引條目。對于我們10億行的表來說,從根節點到葉子節點共需要讀取5層。而對圖1所示的節點來說,只需要讀取3次IO。????
????上面所說的層數,也被成為索引深度。取決于索引鍵的大小和數量。在AdventureWorks示例數據庫中,沒有哪個索引的層級超過3層。但對于其它索引鍵寬或是數據量大的表,就會有更深的層級。????sys.dm_db_index_physical_stats函數可以展示索引的詳細信息,深度和大小。這是一個表值函數,比如下面代碼我們可以找到SalesOrderDetai表相關的索引信息。
得到的結果如圖2所示。
9/9/2012 11:19:21 AM
圖2.查詢sys.dm_db_index_physical_stats函數得到的結果
????
????通過如下代碼我們可以看到更詳細的層級信息.SELECT??OBJECT_NAME(P.OBJECT_ID) AS 'Table' ,
得到的結果如圖3所示。
9/9/2012 11:19:21 AM
圖3.查詢索引的詳細信息通過圖3所示結果,可以看出
- ????葉子節點的條目分布在407頁中
- ????中間節點僅僅需要2頁
- ????根節點只有1頁
????根據索引鍵的選擇,書簽的大小的不同,葉子節點通常是非葉子節點大小的上百倍。根據具體的數據不同而不同。????
????記住包含列僅僅適用在非聚集索引并且只存在于葉子節點中,包含列對于上層的層級是透明的,這也是為什么包含列不會增加非葉子節點鍵的大小。????
????因為聚集索引的葉子節點是表數據本身,所以除了葉子節點的數據是表數據本身之外,還需要存儲一些額外的非葉子層級。因為無論是否有聚集索引數據本身都是存在的,所以創建聚集索引的時候不僅需要花費一些時間和資源,創建成功后還需要一些額外的空間存儲非葉子節點。
總結????
????索引的結構使得SQL Server可以根據鍵值快速找到所需的列,一旦找到所需的列之后,SQL Server可以:
- ????直接訪問所需的行
- ????從找到的數據位置開始,根據雙向鏈表找相鄰的頁
????索引樹結構早已經在沒有關系數據庫時就開始被使用了,事實證明,這是一種優秀的結構。
?
轉載于:https://www.cnblogs.com/lteal/archive/2012/12/03/2799321.html
總結
以上是生活随笔為你收集整理的SQL Server索引进阶第十篇:索引的内部结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AdBlock屏蔽网易的“我来挑错”和“
- 下一篇: [转]十五分钟介绍 Redis数据结构