2010-05-27 124 views
6

此問題是關於插入完成時重新聚集索引中的數據會發生什麼情況。我認爲在具有聚集索引的表上執行插入比在聚集索引中重新組織數據涉及更改磁盤上數據的物理佈局不是一種更昂貴的方式。除了通過我在工作中遇到的一個例子,我不知道如何解釋我的問題。聚集索引 - 多部分索引和單部分索引以及插入/刪除的效果

假設有一個表(垃圾),並且有兩個查詢在表上完成,第一個查詢通過Name進行搜索,第二個查詢通過Name和Something進行搜索。由於我工作的數據庫上我發現表已經有兩個索引創建一個支持每個查詢,像這樣:

--drop table Junk1 
CREATE TABLE Junk1 
(
    Name char(5), 
    Something char(5), 
    WhoCares int 
) 

CREATE CLUSTERED INDEX IX_Name ON Junk1 
(
    Name 
) 

CREATE NONCLUSTERED INDEX IX_Name_Something ON Junk1 
(
    Name, Something 
) 

現在,當我看着這兩個指標,似乎IX_Name是多餘的,因爲IX_Name_Something可以被任何希望按名稱搜索的查詢使用。因此,我將消除IX_Name,使IX_Name_Something聚集索引來代替:

--drop table Junk2 
CREATE TABLE Junk2 
(
    Name char(5), 
    Something char(5), 
    WhoCares int 
) 

CREATE CLUSTERED INDEX IX_Name_Something ON Junk2 
(
    Name, Something 
) 

有人建議,第一編索引方案應保持,因爲這將導致更有效的插入/刪除(假設沒有必要擔心名稱和東西的更新)。這有道理嗎?我認爲第二種索引方法會更好,因爲這意味着需要維護一個較少的索引。

我將不勝感激這個具體的例子或指導我更多關於維護聚集索引的信息。

回答

9

是的,如果您的聚集索引不夠理想,插入現有表(或其頁面)的中間可能會很昂貴。最差的情況是頁面拆分:頁面上的一半行必須移動到其他位置,並且需要更新索引(包括該表上的非聚簇索引)。

您可以通過使用正確的聚集索引緩解這一問題 - 一個理想的是:

  • 窄(只有一個領域,儘可能小)
  • 靜態(永遠不會改變)
  • 獨特的(以便SQL Server並不需要添加4個字節的uniqueifiers你行)
  • 不斷增加(就像INT IDENTITY)

由於每個非聚集索引中的每個條目也都包含集羣鍵,因此您希望使用窄鍵(理想情況下爲單個INT) - 您不希望在聚簇鍵中放置大量列,你也不想把VARCHAR(200)放在那裏!

隨着聚集索引不斷增加,您將永遠無法看到頁面拆分的情況。你可能遇到的唯一碎片是從刪除(「瑞士奶酪」問題)。

退房金佰利特里普對索引excellet博客文章 - 最明顯的是:

假設有一個表(垃圾)和 有兩個查詢被上 完成的表格,第一查詢搜索通過 名,第二個查詢搜索通過 名稱和一些東西。由於我工作的 數據庫中我發現 表已經有兩個 指標,一個爲支持每個查詢, 像這樣:

這絕對不是必需的 - 如果你有一個指數(Name, Something),如果您只搜索並限制WHERE Name = abc - 只有Name列有單獨的索引是完全不需要的,並且只浪費空間(並且花費時間保持最新),那麼該索引也可以並且恰好用於。

所以基本上,你只需要一個索引(Name, Something),我同意你的觀點 - 如果你在這張表上沒有其他索引,那麼你應該可以把它作爲聚簇鍵。既然這個關鍵不會越來越大,並且可能會改變(對嗎?),這可能不是一個好主意。

另一種選擇是引入對替代ID INT IDENTITY和集羣 - 有兩個好處:

  • 這一切都良好的聚集鍵應該是,包括不斷增加 - >你永遠不會有任何與頁拆分和INSERT操作
  • 你仍然可以有一個聚集鍵的所有優勢性能問題(見金特里普斯的博客文章 - 集羣表幾乎都是最好堆)
+1

不錯,徹底的解釋。 – 2010-05-27 21:43:59

0

有人建議,第一編索引方案應保持,因爲它會導致更有效的插入/刪除

這是一個虛假的要求。有序數據是有序數據,並執行相同的IO。

SET STATISTICS IO ON 
-- your insert statement here 
0

只能在一列創建一個聚集索引,而不是兩個或更多這樣選擇您的應用將主要查詢的列,例如通配符查詢客戶fullnames等(見discussion

+0

這是錯誤的,請閱讀: http://msdn.microsoft.com/en-us/library/aa933131(SQL.80).aspx 「表只能包含一個聚集索引,但索引可以包含多列「 – Anssssss 2010-08-31 14:30:52