SQL Server 查詢性能優化——覆蓋索引(一)


覆蓋索引又可以稱為索引覆蓋。
  解釋一: 就是select的數據列只用從索引中就能夠取得,不必從數據表中讀取,換句話說查詢列要被所使用的索引覆蓋。
  解釋二: 索引是高效找到行的一個方法,當能通過檢索索引就可以讀取想要的數據,那就不需要再到數據表中讀取行了。如果一個索引包含了(或覆蓋了)滿足查詢語句中字段與條件的數據就叫做覆蓋索引。
  解釋三: 是非聚集組合索引的一種形式,它包括在查詢里的SelectJoinWhere子句用到的所有列(即建立索引的字段正好是覆蓋查詢語句[select子句]與查詢條件[Where子句]中所涉及的字段,也即,索引包含了查詢正在查找的所有數據)。

 

首先,從聚集索引說起,聚集索引實際上就是一個覆蓋索引,在大多數情況下,可以很直觀地分辨出數據表的當前聚集索引是否有用,因為聚集索引根據鍵值字段控制了數據行的順序。由於SQL SERVER以聚集索引的鍵值字段來排序數據行,所以當你經常需要對某些字段排序時,把這些要排序的字段作為聚集索引的鍵值,創建聚集索引將對查詢性能會有很大的提升。因為數據已經照聚集索引的鍵值字段的順序排序,所以查詢執行時不需要額外的排序操作。同時如果使用聚集索引來查找同條記錄的其他字段的數據,SQL SERVER也不需要額外地通過指針檢索數據,因為在聚集索引找到索引鍵值的同時就已經找到整條數據。

聚集索引在檢索符合某個范圍的數據時也很有用。例如,你想要找到所有銷售訂單編號介於18000-19999的訂單,而聚集索引就是通過銷售訂單編號字段建立的,相近的記錄全部會擺放在一起,則訪問的分頁當然就比較少,通過聚集索引可快速定位包含起始銷售訂單編號的行,然后檢索表中所有連續的行,直到檢索到最后的銷售訂單號。

聚集索引在檢索占總行數比例很大的數據行時也比較有用。

下圖是使用聚集索引查找數據的示意圖。

 

使用聚集索引的好處在於:

   1)所需要的數據都在子葉層(即數據頁),找到正確的索引鍵值后不需要再利用指針做額外的查找

   2SQL SERVER將符合相同條件的數據集中放在一起

 

其次,非聚集索引。非聚集索引結構如下圖。

 

如果想要使建立的非聚集索引同時具備以上兩種好處,那就要建立非聚集覆蓋索引。通過覆蓋索引,所有查詢想要的數據字段都是索引鍵值的一部分,而存放在索引的子葉層級。覆蓋索引不僅僅只包含你寫在WHERE條件內的字段,而且還包含所有SELECT 需要的字段,以及在GROUP BY ORDER BY 子句內的字段。

例:

Select <字段A,B....> from <數據表 T>  where <條件字段C>

SQL SERVER 2000中我們建立覆蓋索引采用以下方式

Create index idx on T(C,A,B) 

 

建立組合索引時,字段的順序很重要,要將條件字段C放在組合索引的第一位,把它做為在索引的上層結構的主要排序對象,且僅有它包含統計數據,也就是非子葉層查找出符合的記錄,然后在存放有其他字段記錄的子葉層讀取所需要的數據。

但是由於字段A,B兩列也會在索引的非子葉層出現,除非WHERE條件是多個字段,或多個字段排序,否則索引非子葉層放在其他數據字段用處不大,徒增索引數據量,減低索引性能。

 

SQL SERVER 2005可以采用以下方式:

Create index idx on T(C) INCLUDE(A,B...)

為了增強覆蓋索引的功能以提升查詢效率,SQL SERVER 2005 Create Index語句中提供INCLUDE參數,將與鍵值列無關的數據表其他字段添加到非聚集索引的子葉層,擴展非聚集索引的功能,但這些字段值不做排序等額外的維護動作。在查詢時僅讀取索引結構就可得到所有相關的數據,不訪問表或聚集索引的數據,從而減少磁盤 I/O 操作,減少讀取數據表本身所花的資源。SQL SERVER 的組合索引最多只能有16個字段,而這些添加到索引子葉層中的相關字段並不計算在這16個字段中。

另外,當查詢優化程序在該索引中可以發現處理查詢所需要的數據,則雖然組合索引的第一個字段不在WHERE條件內,但查詢優化程序仍有可能采取適用的組合索引。或是當查詢語句沒有WHERE條件,但組合索引覆蓋了所有需要的字段時,則直接掃描索引的子葉層獲取數據而不是通過掃描數據表查找數據。

示例:

create  index idx_WBK_PDE_LIST_ORG_HISTROY on [WBK_PDE_LIST_ORG_HISTROY]([WBOOK_NO]) include([QTY_1],[COP_G_NO],[G_NO],[CODE_T],[UNIT_1],[TRADE_TOTAL],[GROSS_WT])

則索引idx_WBK_PDE_LIST_ORG_HISTROY結構中,包含了以WBOOK_NO鍵值順序為主要排序對象的上層結構,以及包含數據表內所有WBOOK_NO與[QTY_1],[COP_G_NO],[G_NO],[CODE_T],[UNIT_1],[TRADE_TOTAL],[GROSS_WT]字段內容的子葉層。如下圖。

 

接下來我用一個實例來解釋一下,上圖中的情況,我們來看看下面這條SQL語句在SQL執行引擎中是如何執行的:

SELECT  G_NO, UNIT_1 FROM [WBK_PDE_LIST_ORG_HISTROY] WHERE [COP_G_NO]= 'BENNET'

 

  1) [WBK_PDE_LIST_ORG_HISTROY] 表在[COP_G_NO]列上有一個非聚集索引,因此它查找非聚集索引的根節點中找出[COP_G_NO]= 'BENNET'的記錄。上圖中1

  2) 從包含[COP_G_NO]= 'BENNET'記錄的索引中間節點中找到指向該記錄的子葉層頁號。上圖中2

  3) 從索引的子葉層中針對每一行數據(假設這里有100條)獲取書簽(由數據庫物理文件編號,對應的Page頁碼,對應的行號組成),SQL Server引擎通過書簽查找從聚集索引或數據表中找出真實的行在對應頁面中的位置。上圖中3

  4) SQL Server引擎從對應的行查找 G_NO和UNIT_1 列的值。

  在上面的步驟中,對[COP_G_NO]= 'BENNET'的所有數據(這里是100條記錄)SQL Server引擎要搜索100次聚集索引或數據表以檢索查詢中指定的其它列( G_NO, UNIT_1 )

  如果非聚集索引頁中包括了查詢語句中所需要的數據列(COP_G_NO,G_NO, UNIT_1)的值,SQL Server引擎可能不會執行上面的第34步,直接從非聚集索引中查找[COP_G_NO]列速度還會快一些,直接從索引的子葉層讀取這三列的數值。


免責聲明!

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



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