SQL索引學習-索引結構


前一陣無意中和同事討論過一個SQL相關的題(通過一個小問題來學習SQL關聯查詢),很慚愧一個非常簡單的問題由於種種原因居然沒有回答正確,數據庫知識方面我算不上技術好,談起SQL知識的學習我得益於2008年進的一家公司,有幾個DBA技術相當專業,正好手上有一個項目遇到了一些數據庫查詢性能問題,就試着想辦法優化,於是自己將相法和DBA溝通后,居然得到了他們的贊同,讓我信心大增,后來一段時間我又主動找他們聊了一些其它的知識,所以在數據庫索引這塊我算是相對一般的.net程序員要更加有見解一些。當時我們部門由於分工的不同,部門20多人基本上工作中從來不和SQL打交道,后台的接口都由其它部門來完成了,我們注意的 業務邏輯,所以有一些完全不懂SQL的程序員。之后的四年我大部分都是做一些通用平台架構方面的工作,也比較少直接接觸SQL,直到后來換了公司,特別是去年開始由於項目性質的變化,我開始慢慢又開始接觸SQL。    

工作時間的長短在某種程度上能決定一個人的技術水平,但往往技術水平和實際工作的產出不一定成正比。比如我上面提到那個SQL問題,很多有經驗的程序員在第一個答案中往往回答錯誤,但他確實能將項目做好,因為大家平時觀注的還是結果,只要結果出來了比什么都強,至於為什么出這樣的結果一般也就不會多做分析研究。這種形式呢,對那些對技術提升沒有強烈要求的人來講,已經夠用了,多試幾次,只要最終能出結果也就萬事大吉了,做的多了,后續遇到類似的問題也就輕車熟路了,這就是所謂的經驗,只知道這樣做就能出結果。    

其實這種工作學習方式呢,有一個比較顯著的問題,就是對自己寫出來的東西沒有足夠的信心,因為靠的是以往的經驗。是出現錯誤之后通過不斷的嘗試來取得的經驗,有一種探索的味道,在工作效率上會存在問題,因為總有你以前沒有遇到過的場景,這樣你可能對第一方案做多次嘗試才找到正解,反之的話,第一個方案可能花的時間稍長一些,但后續反復修改的次數會相當較少。

SQL索引目錄   

借這次機會呢,將SQL索引的理解整理出來,供大家一起學習提高,這是我的學習筆記,有錯誤的地方,歡迎大家批評指正。下面是預計的目錄:

  • 索引基礎知識  
  • 聚集索引  
  • 非聚集索引  
  • 認識執行計划  
  • 靈活設計數據庫      

頁和區

要想做好索引優化,知道索引的存儲結構是至關重要的。談到存儲就需要了解SQL中的頁和區的概念:  

  • SQL中存儲數據的基礎單位就是頁,一個頁大小為8K,數據庫可以將數據從邏輯上分成頁,磁盤的I/O操作就是在頁級執行。頁包信三項內容:
    • 96字節大小的標頭,存儲統計信息,包括頁碼、頁類型、頁的可用空間以及擁有該頁的對象的分配單元 ID。頁類型我們知識如下三項基本就夠用:
      • 數據頁,除了大型對象的數據列之外的數據存儲頁,比如int,float,varchar等。     
      • 索引頁,存放索引的條目。
      • 大型對象數據類型,比如text,image,nvarchar(max)等。        
    • 數據行
    • 行偏移量
  • 一個區包含8個頁,它是管理空間的單位,分為如下兩類
    • 統一區,由單個對象所有。
    • 混合區,最多可由八個對象共享。
  • 一般情況下,給表或者索引申請新的空間時,從混合區分配,當這個表或者索引的空間超過8個頁大小時,會將原本在混合區的頁轉移到統一區管理。

表存儲結構

知識了區以及頁的概念,再看下數據表和這兩者之間的聯系, 表包含一個或多個分區,每個分區在一個堆或一個聚集索引結構中包含數據行。從下圖的結構中,我們就看到了索引的重要結構B-樹了。

            

 

聚集索引結構

索引中的底層節點稱為葉節點。根節點與葉節點之間的任何索引級別統稱為中間級。在聚集索引中,葉節點包含基礎表的數據頁。根節點和中間級節點包含存有索引行的索引頁。每個索引行包含一個鍵值和一個指針,該指針指向 B -樹上的某一中間級頁或葉級索引中的某個數據行。每級索引中的頁均被鏈接在雙向鏈接列表中。

         

非聚集索引結構

           

非聚集索引與聚集索引之間的顯著差別在於以下兩點:

  • 基礎表的數據行不按非聚集鍵的順序排序和存儲。
  • 非聚集索引的葉層是由索引頁而不是由數據頁組成。

問題:

  • 索引的結構到底分多少層?

我們先看下B-樹,這種索引結構有一個重要的參數n,它決定了索引存儲頁的布局,每個存儲頁需要存放n個節點,以及n+1個指針。 這里我們來做個計算:比如我們的索引是一個整形數字,4個字節,指針需要8個字節,這里不考慮索引頁標頭信息的占用,算下最大的n,公式: 4n+8(n+1)<=8*1024 ,這個值是680,即最大可存放680個鍵,再按B-樹充滿度來取75%等於510,根結點有510個,那么它會有510*510個葉結點,這些葉結點會有510*510*510個指向最終記錄的指針。這個數據足以說明絕多數情況下,只要三層就能夠用。

  • 什么是稠密索引?

索引中的鍵順序與數據文件中的排序順序相同,所以我們的索引結構中,葉級均采用稿密索引。

  • 什么是稀疏索引?

它只為每個存儲塊設計鍵-指針對,比稿密索引節約空間,出現在葉級之上的結構中。

  • 索引結構中會出現如下情況嗎?

要想回答這個問題,就需要了解索引在維護過程中對於B-樹的調整,SQL會通過一定的算法將B-樹的充滿度達到一定的平衡,這里就會涉及的節點的拆分以及合並,所以一般情況下無論對數據做怎樣的更新,也不會出現下圖中如此不平衡的情況。

注:如果問重建索引的好處時,如果你回答是為了平衡B-樹,那么要謹慎回答。

   

總結

      數據存儲的基礎知識,索引結構對於我們后續理解聚集索引以及非聚集索引都非常重要,也才有可能快速准確的做出優化方案。

參考:http://technet.microsoft.com/zh-cn/library/ms180978(v=sql.105).aspx

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM