覆寫索引又可以稱為索引覆寫。
解釋一: 就是select的資料列隻用從索引中就能夠取得,不必從資料表中讀取,換句話說查詢列要被所使用的索引覆寫。
解釋二: 索引是高效找到行的一個方法,當能通過檢索索引就可以讀取想要的資料,那就不需要再到資料表中讀取行了。如果一個索引包含了(或覆寫了)滿足查詢語句中字段與條件的資料就叫做覆寫索引。
解釋三: 是非聚集組合索引的一種形式,它包括在查詢裡的Select、Join和Where子句用到的所有列(即建立索引的字段正好是覆寫查詢語句[select子句]與查詢條件[Where子句]中所涉及的字段,也即,索引包含了查詢正在查找的所有資料)。
首先,從聚集索引說起,聚集索引實際上就是一個覆寫索引,在大多數情況下,可以很直覺地分辨出資料表的目前聚集索引是否有用,因為聚集索引根據鍵值字段控制了資料行的順序。由于SQL SERVER以聚集索引的鍵值字段來排序資料行,是以當你經常需要對某些字段排序時,把這些要排序的字段作為聚集索引的鍵值,建立聚集索引将對查詢性能會有很大的提升。因為資料已經照聚集索引的鍵值字段的順序排序,是以查詢執行時不需要額外的排序操作。同時如果使用聚集索引來查找同條記錄的其他字段的資料,SQL SERVER也不需要額外地通過指針檢索資料,因為在聚集索引找到索引鍵值的同時就已經找到整條資料。
聚集索引在檢索符合某個範圍的資料時也很有用。例如,你想要找到所有銷售訂單編号介于18000-19999的訂單,而聚集索引就是通過銷售訂單編号字段建立的,相近的記錄全部會擺放在一起,則通路的分頁當然就比較少,通過聚集索引可快速定位包含起始銷售訂單編号的行,然後檢索表中所有連續的行,直到檢索到最後的銷售訂單号。
聚集索引在檢索占總行數比例很大的資料行時也比較有用。
下圖是使用聚集索引查找資料的示意圖。
使用聚集索引的好處在于:
1)所需要的資料都在子葉層(即資料頁),找到正确的索引鍵值後不需要再利用指針做額外的查找
2)SQL 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 列的值。