2008-11-10 34 views
29

我正在處理通常使用GUID作爲主鍵的數據庫。我應該擺脫Guid列上的聚簇索引

默認情況下,SQL Server在主鍵列上放置聚簇索引。我知道這對於GUID列是一個愚蠢的想法,非聚集索引更好。

你認爲 - 我應該擺脫所有的聚集索引,並用非聚集索引取代它們嗎?

爲什麼SQL的性能調諧器不提供這個建議?

+0

看看Paul Randal撰寫的以下文章。 [隨機GUID上的羣集索引或非羣集索引?](http://www.sqlskills.com/blogs/paul/clustered-or-nonclustered-index-on-a-random-guid/) – Lijo 2016-09-09 20:55:57

回答

25

聚集索引的一個重要原因是您經常想要檢索給定列的某個範圍值的行。由於數據按照該順序物理排列,所以可以非常有效地提取行。

某些像GUID一樣優秀的主鍵可能會對性能產生積極的不利影響,因爲插入會帶來額外的成本,而且對選擇沒有明顯的好處。

所以是的,不要在GUID上集羣索引。至於爲什麼它不作爲推薦提供,我建議調諧器意識到這一事實。

+2

使用SQL 2005和newsequentialid(),碎片問題在很大程度上消失。最好通過查看sys.dm_db_index_physical_stats和sys_indexes來進行衡量。 – RoadWarrior 2008-11-10 17:12:04

+0

儘管如此,您仍然無法在您的查詢中獲得任何好處。如果你需要,你應該只聚集在`UNIQUEIDENTIFIER`上。用於複製。 – 2016-06-27 22:29:52

4

GUID字段中聚簇索引的問題是GUID是隨機的,所以當插入新記錄時,磁盤上的大部分數據必須移動以將記錄插入到表的中間。

但是,對於基於整數的聚簇索引,整數通常是順序的(就像IDENTITY規範),所以它們只是被添加到最後而沒有數據需要移動。

另一方面,聚簇索引並不總是在GUID上不好......這一切都取決於您的應用程序的需求。如果您需要能夠快速記錄SELECT,那麼使用聚簇索引... INSERT速度會受到影響,但SELECT的速度會有所提高。

0

是的,你應該刪除GUID主鍵上的聚簇索引,原因是Galwegian上面所述的原因。我們已經在我們的應用程序上做到了

0

這取決於你是否做了很多插入操作,或者是否需要通過PK快速查找。

+0

羣集不會影響查找速度 - 一個獨特的非聚集索引應該做的工作。 – 2008-11-10 11:18:59

4

如果您使用的是NewId(),則可以切換到NewSequentialId()。這應該有助於插入性能。

5

雖然在GUID上進行羣集通常是一個壞主意,但請注意,在某些情況下,GUID可能爲 cause fragmentation even in non-clustered indexes

請注意,如果您使用的是SQL Server 2005,則newsequentialid()函數會生成連續的 GUID。這有助於防止碎片問題。

我建議使用像一個SQL查詢的以下測量裂解作出任何決定之前,(原諒非ANSI語法):

SELECT OBJECT_NAME (ips.[object_id]) AS 'Object Name', 
     si.name AS 'Index Name', 
     ROUND (ips.avg_fragmentation_in_percent, 2) AS 'Fragmentation', 
     ips.page_count AS 'Pages', 
     ROUND (ips.avg_page_space_used_in_percent, 2) AS 'Page Density' 
FROM sys.dm_db_index_physical_stats 
    (DB_ID ('MyDatabase'), NULL, NULL, NULL, 'DETAILED') ips 
CROSS APPLY sys.indexes si 
WHERE si.object_id = ips.object_id 
AND si.index_id = ips.index_id 
AND ips.index_level = 0; 
2

是的,有沒有點上的隨機值有一個聚集索引。

您可能確實希望在您的數據庫中使用聚簇索引SOMEWHERE。例如,如果您有一個「Author」表和一個「Book」表以及一個帶有「Author」的外鍵,並且您的應用程序中有一個查詢,「select ... from Book where AuthorId = .. 「,那麼你會閱讀一套書。如果這些書在磁盤上彼此相鄰,那麼它將會更快,因此磁盤頭不必在各個部門之間反彈,從而收集該作者的所有書籍。

因此,您需要考慮應用程序以及查詢數據庫的方式。

進行更改。

然後進行測試,因爲你永遠不知道...

24

你幾乎肯定要建立在每一個表中的聚集索引在數據庫中。 如果一個表沒有聚簇索引,它就是所謂的「堆」,大多數類型的常見查詢的性能是less for a heap than for a clustered index table

應該建立聚簇索引的哪些字段取決於表本身以及針對該表的查詢的預期使用模式。在幾乎每種情況下,您可能都希望聚簇索引位於唯一的列或列組合上,即(備用鍵),因爲如果不是,SQL將爲唯一值添加唯一值無論如何您選擇的字段。如果您的表中有一列或多列用於查詢以便選擇或過濾多個記錄(例如,如果您的表格包含銷售交易,並且您的應用程序會經常按產品ID請求銷售交易,或者更好,一張發票詳細信息表,在幾乎所有情況下,您都將檢索特定發票的所有明細記錄,或者您經常檢索特定客戶的所有發票的發票表......無論您選擇大單個值或一系列值的記錄數)

這些列是聚簇索引的候選項。聚集索引中列的順序很關鍵。索引中定義的第一列應該是首先在預期查詢中選擇或過濾的列。

所有這些的理由是基於理解數據庫索引的內部結構。這些指數被稱爲平衡樹(B-Tree)指數。它們有點像二叉樹,只是樹中的每個節點可以有任意數量的條目(和子節點),而不是僅有兩個。使聚簇索引不同的是,聚簇索引中的葉節點是該表本身的實際物理磁盤數據頁面。而非聚集索引的葉節點只是「指向」表的數據頁面。

因此,當表具有clsutered索引時,表數據頁是該索引的葉級別,並且每個表都具有指向索引順序中的前一頁和下一頁的指針(它們形成雙向索引,鏈表)。

因此,如果您的查詢請求一系列與聚簇索引相同順序的行......處理器只需遍歷索引一次(或者兩次),即可找到數據的起始頁,然後按照鏈接列表指針轉到下一頁和下一頁,直到它已經讀取了它需要的所有數據頁面。

對於一個非聚集索引,它必須遍歷它檢索到的每一行索引...

注意:編輯
要解決Guid Key列的順序問題,請注意SQL2k5具有NEWSEQUENTIALID(),實際上它會生成Guid的「舊」順序方式。

,或者你可以調查吉米Nielsens梳,它在客戶端代碼中實現GUID algotithm:

COMB Guids

0

由於大多數所提到的,避免在聚集索引中使用隨機標識符 - 您將無法獲得聚類的好處。其實,你會經歷一個延遲。擺脫所有這些都是可靠的建議。另外請記住,在多主複製場景中,newsequentialid()可能會出現問題。如果數據庫A和B在複製之前都調用newsequentialid(),則會發生衝突。