聚簇索引与非聚簇索引学习总结
生活随笔
收集整理的這篇文章主要介紹了
聚簇索引与非聚簇索引学习总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
聚簇索引與非聚簇索引的區別
? ? 通常情況下,建立索引是加快查詢速度的有效手段。但索引不是萬能的,靠索引并不能實現對所有
數據的快速存取。事實上,如果索引策略和數據檢索需求嚴重不符的話,建立索引反而會降低查詢性能
。因此在實際使用當中,應該充分考慮到索引的開銷,包括磁盤空間的開銷及處理開銷(如資源競爭和
加鎖)。例如,如果數據頻繁的更新或刪加,就不宜建立索引。
? ? 本文簡要討論一下聚簇索引的特點及其與非聚簇索引的區別。
建立索引:
在SQL語言中,建立聚簇索引使用CREATE INDEX語句,格式為:CREATE CLUSTER INDEX index_name ON?
table_name(column_name1,column_name2,...);
存儲特點:
聚集索引。表數據按照索引的順序來存儲的,也就是說索引項的順序與表中記錄的物理順序一致。對于
聚集索引,葉子結點即存儲了真實的數據行,不再有另外單獨的數據頁。 在一張表上最多只能創建一個
聚集索引,因為真實數據的物理順序只能有一種。
非聚集索引。表數據存儲順序與索引順序無關。對于非聚集索引,葉結點包含索引字段值及指向數據頁
數據行的邏輯指針,其行數量與數據表行數據量一致。
? ? 總結一下:聚集索引是一種稀疏索引,數據頁上一級的索引頁存儲的是頁指針,而不是行指針。而
對于非聚集索引,則是密集索引,在數據頁的上一級索引頁它為每一個數據行存儲一條索引記錄。
更新表數據
1、向表中插入新數據行
? ? 如果一張表沒有聚集索引,那么它被稱為“堆集”(Heap)。這樣的表中的數據行沒有特定的順序
,所有的新行將被添加到表的末尾位置。而建立了聚簇索引的數據表則不同:最簡單的情況下,插入操
作根據索引找到對應的數據頁,然后通過挪動已有的記錄為新數據騰出空間,最后插入數據。如果數據
頁已滿,則需要拆分數據頁,調整索引指針(且如果表還有非聚集索引,還需要更新這些索引指向新的
數據頁)。而類似于自增列為聚集索引的,數據庫系統可能并不拆分數據頁,而只是簡單的新添數據頁
。
2、從表中刪除數據行
? ? 對刪除數據行來說:刪除行將導致其下方的數據行向上移動以填充刪除記錄造成的空白。如果刪除
的行是該數據頁中的最后一行,那么該數據頁將被回收,相應的索引頁中的記錄將被刪除。對于數據的
刪除操作,可能導致索引頁中僅有一條記錄,這時,該記錄可能會被移至鄰近的索引頁中,原索引頁將
被回收,即所謂的“索引合并”。
========
數據庫中聚簇索引與非聚簇索引的區別
在《數據庫原理》里面,對聚簇索引的解釋是:聚簇索引的順序就是數據的物理存儲順序,而對非聚簇索
引的解釋是:索引順序與數據物理排列順序無關。正式因為如此,所以一個表最多只能有一個聚簇索引
在《數據庫原理》里面,對聚簇索引的解釋是:聚簇索引的順序就是數據的物理存儲順序,而對非聚簇索
引的解釋是:索引順序與數據物理排列順序無關。正式因為如此,所以一個表最多只能有一個聚簇索引。
不過這個定義太抽象了。在SQL Server中,索引是通過二叉樹的數據結構來描述的,我們可以這么理解
聚簇索引:索引的葉節點就是數據節點。而非聚簇索引的葉節點仍然是索引節點,只不過有一個指針指
向對應的數據塊。如下圖:
非聚簇索引
?
聚簇索引
聚簇索引與非聚簇索引的本質區別到底是什么?什么時候用聚簇索引,什么時候用非聚簇索引?
這是一個很復雜的問題,很難用三言兩語說清楚。我在這里從SQL Server索引優化查詢的角度簡單談談(
如果對這方面感興趣的話,可以讀一讀微軟出版的《Microsoft SQL Server 2000數據庫編程》第3單元
的數據結構引論以及第6、13、14單元)。
一、索引塊與數據塊的區別
大家都知道,索引可以提高檢索效率,因為它的二叉樹結構以及占用空間小,所以訪問速度塊。讓我們
來算一道數學題:如果表中的一條記錄在磁盤上占用 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自動維護統計信息,這些統計信息包括數據密度信息以及數據分布信
息,這些信息幫助SQL Server決定如何制定查詢計劃以及查詢是是否使用索引以及使用什么樣的索引(
這里就不再解釋它們到底如何幫助SQL Server建立查詢計劃的了)。我們還是來做個實驗。建立一張表
:tabTest(ID, unqValue,intValue),其中ID是整形自動編號主索引,unqValue是uniqueidentifier類
型,在上面建立普通索 引,intValue 是整形,不建立索引。之所以掛上一個沒有索引的intValue字段
,就是防止SQL Server使用索引覆蓋查詢優化技術,這樣實驗就起不到作用了。向表中錄入10000條隨機
記錄,代碼如下:
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使用了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個中間節點,至于會不會出現重復必須檢索另外1000
個頁數據節點 才知道,那么相當于檢索10+1000=1010個頁面才知道是否有重復。所以聚簇索引主鍵的插
入速度要比非聚簇索引主鍵的插入速度慢很多。
讓我們再來看看數據檢索的效率,如果對上述兩表進行檢索,在使用索引的情況下(有些時候SQL?
Server執行計劃會選擇不使用索引,不過我們這里姑且假設一定使用索引),對于聚簇索引檢索,我們
可能會訪問10個索引頁面外加1000個數據頁面得 到結果(實際情況要比這個好),而對于非聚簇索引,
系統會從20個頁面中找到符合條件的節點,再映射到1000個數據頁面上(這也是最糟糕的情況),比較?
一下,一個訪問了1010個頁面而另一個訪問了1020個頁面,可見檢索效率差異并不是很大。所以不管非
聚簇索引也好還是聚簇索引也好,都適合排序,聚簇 索引僅僅比非聚簇索引快一點。
結語
好了,寫了半天,手都累了。關于聚簇索引與非聚簇索引效率問題的實驗就不做了,感興趣的話可以自
己使用查詢分析器對查詢計劃進行分析。SQL Server是一個很復雜的系統,尤其是索引以及查詢優化技
術,Oracle就更復雜了。了解索引以及查詢背后的事情不是什么壞事,它可以幫助我們更為深 刻的了解
我們的系統。
========
總結
以上是生活随笔為你收集整理的聚簇索引与非聚簇索引学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 语法树学习总结
- 下一篇: Android Bundle类 学习总结