聚集索引和非聚集索引

作者: min10  來源: 博客園  發布時間: 2008-12-22 21:52  閱讀: 22534 次  推薦: 16   原文鏈接   [收藏]  

聚集索引的區別

  聚集索引:物理存儲按照索引排序

  非聚集索引:物理存儲不按照索引排序

優勢與缺點

聚集索引:插入數據時速度要慢(時間花費在“物理存儲的排序”上,也就是首先要找到位置然后插入),查詢數據比非聚集數據的速度快

聚集索引的區別

  聚集索引:物理存儲按照索引排序

  非聚集索引:物理存儲不按照索引排序

優勢與缺點

聚集索引:插入數據時速度要慢(時間花費在“物理存儲的排序”上,也就是首先要找到位置然后插入),查詢數據比非聚集數據的速度快

索引是通過二叉樹的數據結構來描述的,我們可以這么理解聚簇索引:索引的葉節點就是數據節點。而非聚簇索引的葉節點仍然是索引節點,只不過有一個指針指向對應的數據塊。如下圖:

非聚集索引

聚集索引

一、索引塊與數據塊的區別

大家都知道,索引可以提高檢索效率,因為它的二叉樹結構以及占用空間小,所以訪問速度塊。讓我們來算一道數學題:如果表中的一條記錄在磁盤上占用1000字節的話,我們對其中10字節的一個字段建立索引,那么該記錄對應的索引塊的大小只有10字節。我們知道,SQL Server的最小空間分配單元是“頁(Page)”,一個頁在磁盤上占用8K空間,那么這一個頁可以存儲上述記錄8條,但可以存儲索引800條。現在我們要從一個有8000條記錄的表中檢索符合某個條件的記錄,如果沒有索引的話,我們可能需要遍歷8000條×1000字節/8K字節=1000個頁面才能夠找到結果。如果在檢索字段上有上述索引的話,那么我們可以在8000條×10字節/8K字節=10個頁面中就檢索到滿足條件的索引塊,然后根據索引塊上的指針逐一找到結果數據塊,這樣IO訪問量要少的多。

二、索引優化技術

是不是有索引就一定檢索的快呢?答案是否。有些時候用索引還不如不用索引快。比如說我們要檢索上述表中的所有記錄,如果不用索引,需要訪問8000條×1000 字節/8K字節=1000個頁面,如果使用索引的話,首先檢索索引,訪問8000條×10字節/8K字節=10個頁面得到索引檢索結果,再根據索引檢索結果去對應數據頁面,由于是檢索所有數據,所以需要再訪問8000條×1000字節/8K字節=1000個頁面將全部數據讀取出來,一共訪問了1010個頁面,這顯然不如不用索引快。

SQL Server內部有一套完整的數據檢索優化技術,在上述情況下,SQL Server的查詢計劃(Search Plan)會自動使用表掃描的方式檢索數據而不會使用任何索引。那么SQL Server是怎么知道什么時候用索引,什么時候不用索引的呢?SQL Server除了日常維護數據信息外,還維護著數據統計信息,下圖是數據庫屬性頁面的一個截圖:

 

聚簇索引與非聚簇索引的本質區別到底是什么?什么時候用聚簇索引,什么時候用非聚簇索引?

這是一個很復雜的問題,很難用三言兩語說清楚。我在這里從SQL Server索引優化查詢的角度簡單談談(如果對這方面感興趣的話,可以讀一讀微軟出版的《Microsoft SQL Server 2000數據庫編程》第3單元的數據結構引論以及第6、13、14單元)。
從圖中我們可以看到,SQL Server自動維護統計信息,這些統計信息包括數據密度信息以及數據分布信息,這些信息幫助SQL Server決定如何制定查詢計劃以及查詢是是否使用索引以及使用什么樣的索引(這里就不再解釋它們到底如何幫助SQL Server建立查詢計劃的了)。我們還是來做個實驗。建立一張表:tabTest(ID, unqValue,intValue),其中ID是整形自動編號主索引,unqValue是uniqueidentifier類型,在上面建立普通索引,intValue 是整形,不建立索引。之所以掛上一個沒有索引的intValue字段,就是防止SQL Server使用索引覆蓋查詢優化技術,這樣實驗就起不到作用了。向表中錄入10000條隨機記錄,代碼如下:

Code

然后我們執行兩個查詢并查看執行計劃,如圖:(在查詢分析器的查詢菜單中可以打開查詢計劃,同時圖上第一個查詢的GUID是我從數據庫中找的,大家做實驗的時候可以根據自己數據庫中的值來定):

 從圖中可以看出,在第一個查詢中,SQL Server使用了IX_tabTest_unqValue索引,根據箭頭方向,計算機先在索引范圍內找,找到后,使用Bookmark Lookup將索引節點映射到數據節點上,最后給出SELECT結果。在第二個查詢中,系統直接遍歷表給出結果,不過它使用了聚簇索引,為什么呢?不要忘了,聚簇索引的頁節點就是數據節點!這樣使用聚簇索引會更快一些(不受數據刪除、更新留下的存儲空洞的影響,直接遍歷數據是要跳過這些空洞的)。

下面,我們在SQL Server中將ID字段的聚簇索引更改為非聚簇索引,然后再執行select * from tabTest,這回我們看到的執行計劃變成了:

SQL Server沒有使用任何索引,而是直接執行了Table Scan,因為只有這樣,檢索效率才是最高的。


三、聚簇索引與非聚簇索引的本質區別

現在可以討論聚簇索引與非聚簇索引的本質區別了。正如本文最前面的兩個圖所示,聚簇索引的葉節點就是數據節點,而非聚簇索引的頁節點仍然是索引檢點,并保留一個鏈接指向對應數據塊。

還是通過一道數學題來看看它們的區別吧:假設有一8000條記錄的表,表中每條記錄在磁盤上占用1000字節,如果在一個10字節長的字段上建立非聚簇索引主鍵,需要二叉樹節點16000個(這16000個節點中有8000個葉節點,每個頁節點都指向一個數據記錄),這樣數據將占用8000條×1000字節 /8K字節=1000個頁面;索引將占用16000個節點×10字節/8K字節=20個頁面,共計1020個頁面。

同樣一張表,如果我們在對應字段上建立聚簇索引主鍵,由于聚簇索引的頁節點就是數據節點,所以索引節點僅有8000個,占用10個頁面,數據仍然占有1000個頁面。

下面我們看看在執行插入操作時,非聚簇索引的主鍵為什么比聚簇索引主鍵要快。主鍵約束要求主鍵不能出現重復,那么SQL Server是怎么知道不出現重復的呢?唯一的方法就是檢索。對于非聚簇索引,只需要檢索20個頁面中的16000個節點就知道是否有重復,因為所有主鍵鍵值在這16000個索引節點中都包含了。但對于聚簇索引,索引節點僅僅包含了8000個中間節點,至于會不會出現重復必須檢索另外8000個頁數據節點才知道,那么相當于檢索10+1000=1010個頁面才知道是否有重復。所以聚簇索引主鍵的插入速度要比非聚簇索引主鍵的插入速度慢很多。

讓我們再來看看數據檢索的效率,如果對上述兩表進行檢索,在使用索引的情況下(有些時候SQL Server執行計劃會選擇不使用索引,不過我們這里姑且假設一定使用索引),對于聚簇索引檢索,我們可能會訪問10個索引頁面外加1000個數據頁面得到結果(實際情況要比這個好),而對于非聚簇索引,系統會從20個頁面中找到符合條件的節點,再映射到1000個數據頁面上(這也是最糟糕的情況),比較一下,一個訪問了1010個頁面而另一個訪問了1020個頁面,可見檢索效率差異并不是很大。所以不管非聚簇索引也好還是聚簇索引也好,都適合排序,聚簇索引僅僅比非聚簇索引快一點。

結語

關于聚簇索引與非聚簇索引效率問題的實驗就不做了,感興趣的話可以自己使用查詢分析器對查詢計劃進行分析。SQL Server是一個很復雜的系統,尤其是索引以及查詢優化技術,Oracle就更復雜了。了解索引以及查詢背后的事情不是什么壞事,它可以幫助我們更為深刻的了解我們的系統。

-------------------------------------

非聚簇對于更新肯定是有優勢的
而它在檢索的性能損失也不會太大

所以能不用聚簇當然是最好的了
但是如果使用\order by的話 
聚簇的優勢也應該是很明顯的

-------------------------------------

   索引有兩種類型:聚簇索引和非聚簇索引。

在聚簇索引中,索引樹的葉級頁包含實際的數據:記錄的索引順序與物理順序相同。
在非聚簇索引中,葉級頁指向表中的記錄:記錄的物理順序與邏輯順序沒有必然的聯系。

聚簇索引非常象目錄表,目錄表的順序與實際的頁碼順序是一致的。非聚簇索引則更象書的標準索引表,索引表中的順序通常與實際的頁碼順序是不一致的。一本書也許有多個索引。例如,它也許同時有主題索引和作者索引。同樣,一個表可以有多個非聚簇索引。

通常情況下,你使用的是聚簇索引,但是你應該對兩種類型索引的優缺點都有所理解。

每個表只能有一個聚簇索引,因為一個表中的記錄只能以一種物理順序存放。通常你要對一個表按照標識字段建立聚簇索引。但是,你也可以對其它類型的字段建立聚簇索引,如字符型,數值型和日期時間型字段。
從建立了聚簇索引的表中取出數據要比建立了非聚簇索引的表快。當你需要取出一定范圍內的數據時,用聚簇索引也比用非聚簇索引好。例如,假設你用一個表來記錄訪問者在你網點上的活動。如果你想取出在一定時間段內的登錄信息,你應該對這個表的DATETIME型字段建立聚簇索引。
對聚簇索引的主要限制是每個表只能建立一個聚簇索引。但是,一個表可以有不止一個非聚簇索引。實際上,對每個表你最多可以建立249個非聚簇索引。你也可以對一個表同時建立聚簇索引和非聚簇索引。
假如你不僅想根據日期,而且想根據用戶名從你的網點活動日志中取數據。在這種情況下,同時建立一個聚簇索引和非聚簇索引是有效的。你可以對日期時間字段建立聚簇索引,對用戶名字段建立非聚簇索引。如果你發現你需要更多的索引方式,你可以增加更多的非聚簇索引。
非聚簇索引需要大量的硬盤空間和內存。另外,雖然非聚簇索引可以提高從表中取數據的速度,它也會降低向表中插入和更新數據的速度。每當你改變了一個建立了非聚簇索引的表中的數據時,必須同時更新索引。因此你對一個表建立非聚簇索引時要慎重考慮。如果你預計一個表需要頻繁地更新數據,那么不要對它建立太多非聚簇索引。另外,如果硬盤和內存空間有限,也應該限制使用非聚簇索引的數量。

索引屬性

這兩種類型的索引都有兩個重要屬性:
你可以用兩者中任一種類型同時對多個字段建立索引(復合索引);
兩種類型的索引都可以指定為唯一索引。
你可以對多個字段建立一個復合索引,甚至是復合的聚簇索引。假如有一個表記錄了你的網點訪問者的姓和名字。如果你希望根據完整姓名從表中取數據,你需要建立一個同時對姓字段和名字字段進行的索引。這和分別對兩個字段建立單獨的索引是不同的。當你希望同時對不止一個字段進行查詢時,你應該建立一個對多個字段的索引。如果你希望對各個字段進行分別查詢,你應該對各字段建立獨立的索引。
兩種類型的索引都可以被指定為唯一索引。如果對一個字段建立了唯一索引,你將不能向這個字段輸入重復的值。一個標識字段會自動成為唯一值字段,但你也可以對其它類型的字段建立唯一索引。假設你用一個表來保存你的網點的用戶密碼,你當然不希望兩個用戶有相同的密碼。通過強制一個字段成為唯一值字段,你可以防止這種情況的發生。 

http://hi.baidu.com/guobeilei/blog/item/51f55afbda311e116c22eb0e.html

 

聚集索引基于數據行的鍵值在表內排序和存儲這些數據行。每個表只能有一個聚集索引,因為數據行本身只能按一個順序存儲。有關聚集索引體系結構的詳細信息,請參閱聚集索引結構。

每個表幾乎都對列定義聚集索引來實現下列功能:

  • 可用于經常使用的查詢。
  • 提供高度唯一性。
     
    注意:
    創建 PRIMARY KEY 約束時,將在列上自動創建唯一索引。默認情況下,此索引是聚集索引,但是在創建約束時,可以指定創建非聚集索引。

     

     

  • 可用于范圍查詢。

如果未使用 UNIQUE 屬性創建聚集索引,數據庫引擎將向表自動添加一個 4 字節的 uniqueifier 列。必要時,數據庫引擎將向行自動添加一個 uniqueifier 值以使每個鍵唯一。此列和列值供內部使用,用戶不能查看或訪問。

查詢注意事項

在創建聚集索引之前,應先了解數據是如何被訪問的。考慮對具有以下特點的查詢使用聚集索引:

  • 使用運算符(如 BETWEEN、>、>=、< 和 <=)返回一系列值。

    使用聚集索引找到包含第一個值的行后,便可以確保包含后續索引值的行物理相鄰。例如,如果某個查詢在一系列銷售訂單號間檢索記錄,SalesOrderNumber 列的聚集索引可快速定位包含起始銷售訂單號的行,然后檢索表中所有連續的行,直到檢索到最后的銷售訂單號。
  • 返回大型結果集。
  • 使用 JOIN 子句;一般情況下,使用該子句的是外鍵列。
  • 使用 ORDER BY 或 GROUP BY 子句。

    在 ORDER BY 或 GROUP BY 子句中指定的列的索引,可以使數據庫引擎不必對數據進行排序,因為這些行已經排序。這樣可以提高查詢性能。

列注意事項

一般情況下,定義聚集索引鍵時使用的列越少越好。考慮具有下列一個或多個屬性的列:

  • 唯一或包含許多不重復的值

    例如,雇員 ID 唯一地標識雇員。EmployeeID 列的聚集索引或 PRIMARY KEY 約束將改善基于雇員 ID 號搜索雇員信息的查詢的性能。另外,可對 LastNameFirstNameMiddleName 列創建聚集索引,因為經常以這種方式分組和查詢雇員記錄,而且這些列的組合還可提供高區分度。
  • 按順序被訪問

    例如,產品 ID 唯一地標識 AdventureWorks 數據庫的 Production.Product 表中的產品。在其中指定順序搜索的查詢(如 WHERE ProductID BETWEEN 980 and 999)將從 ProductID 的聚集索引受益。這是因為行將按該鍵列的排序順序存儲。
  • 由于保證了列在表中是唯一的,所以定義為 IDENTITY。
  • 經常用于對表中檢索到的數據進行排序。

    按該列對表進行聚集(即物理排序)是一個好方法,它可以在每次查詢該列時節省排序操作的成本。

聚集索引不適用于具有下列屬性的列:

  • 頻繁更改的列

    這將導致整行移動,因為數據庫引擎必須按物理順序保留行中的數據值。這一點要特別注意,因為在大容量事務處理系統中數據通常是可變的。
  • 寬鍵

    寬鍵是若干列或若干大型列的組合。所有非聚集索引將聚集索引中的鍵值用作查找鍵。為同一表定義的任何非聚集索引都將增大許多,這是因為非聚集索引項包含聚集鍵,同時也包含為此非聚集索引定義的鍵列。

索引選項

創建聚集索引時,可指定若干索引選項。因為聚集索引通常都很大,所以應特別注意下列選項:

  • SORT_IN_TEMPDB
  • DROP_EXISTING
  • FILLFACTOR
  • ONLINE
16
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()