聚集索引的區別
聚集索引:物理存儲按照索引排序
非聚集索引:物理存儲不按照索引排序
優勢與缺點
聚集索引:插入數據時速度要慢(時間花費在“物理存儲的排序”上,也就是首先要找到位置然后插入),查詢數據比非聚集數據的速度快
聚集索引的區別
聚集索引:物理存儲按照索引排序
非聚集索引:物理存儲不按照索引排序
優勢與缺點
聚集索引:插入數據時速度要慢(時間花費在“物理存儲的排序”上,也就是首先要找到位置然后插入),查詢數據比非聚集數據的速度快
索引是通過二叉樹的數據結構來描述的,我們可以這么理解聚簇索引:索引的葉節點就是數據節點。而非聚簇索引的葉節點仍然是索引節點,只不過有一個指針指向對應的數據塊。如下圖:
非聚集索引
聚集索引
一、索引塊與數據塊的區別
大 家都知道,索引可以提高檢索效率,因為它的二叉樹結構以及占用空間小,所以訪問速度塊。讓我們來算一道數學題:如果表中的一條記錄在磁盤上占用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 CREATE TABLE [dbo].[tabTest] ( [ID] [int] IDENTITY (1, 1) NOT NULL , [unqValue] [uniqueidentifier] NOT NULL , [intValue] [int] NOT NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[tabTest] WITH NOCHECK ADD CONSTRAINT [PK_tabTest] PRIMARY KEY CLUSTERED ( [ID] ) ON [PRIMARY] GO ALTER TABLE [dbo].[tabTest] ADD CONSTRAINT [DF_tabTest_unqValue] DEFAULT (newid()) FOR [unqValue] GO CREATE INDEX [IX_tabTest_unqValue] ON [dbo].[tabTest]([unqValue]) ON [PRIMARY] GO declare @i int declare @v int set @i=0 while @i<10000 begin set @v=rand()*1000 insert into tabTest ([intValue]) values (@v) set @i=@i+1 end
然后我們執行兩個查詢並查看執行計划,如圖:(在查詢分析器的查詢菜單中可以打開查詢計划,同時圖上第一個查詢的GUID是我從數據庫中找的,大家做實驗的時候可以根據自己數據庫中的值來定):
下面,我們在SQL Server中將ID字段的聚簇索引更改為非聚簇索引,然后再執行select * from tabTest,這回我們看到的執行計划變成了:

三、聚簇索引與非聚簇索引的本質區別
現在可以討論聚簇索引與非聚簇索引的本質區別了。正如本文最前面的兩個圖所示,聚簇索引的葉節點就是數據節點,而非聚簇索引的頁節點仍然是索引檢點,並保留一個鏈接指向對應數據塊。
還 是通過一道數學題來看看它們的區別吧:假設有一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
聚集索引基於數據行的鍵值在表內排序和存儲這些數據行。每個表只能有一個聚集索引,因為數據行本身只能按一個順序存儲。有關聚集索引體系結構的詳細信息,請參閱聚集索引結構。
每個表幾乎都對列定義聚集索引來實現下列功能:
可用於經常使用的查詢。 提供高度唯一性。
可用於范圍查詢。
如果未使用 UNIQUE 屬性創建聚集索引,數據庫引擎將向表自動添加一個 4 字節的 uniqueifier列。必要時,數據庫引擎將向行自動添加一個 uniqueifier 值以使每個鍵唯一。此列和列值供內部使用,用戶不能查看或訪問。