2014-03-06 56 views
0

感謝精彩文章The Cost of GUIDs as Primary Keys,我們有COMB GUID。基於當前實現,有2種方法:8個字節的時間戳或6個字節的時間戳記COMB GUID在SQLServer

  1. 利用最後6個字節的時間戳:GUIDs as fast primary keys under multiple databases
  2. 使用最後8個使用字節時間戳窗口勾選:GUID COMB strategy in EF4.1 (CodeFirst)

我們都知道, GUID爲6字節的時間戳,隨機字節的字節數將減少,以減少GUID的衝突。但是會創建更多具有相同時間戳的GUID,並且這些GUID根本不是順序的。因此,8字節的時間戳將是首選。

所以這似乎是一個艱難的選擇。基於商品上方GUIDs as fast primary keys under multiple databases,它說:

在我們繼續之前,短註腳對這種做法:使用1毫秒的分辨率時間戳指的GUID產生非常接近可能具有相同的時間戳值,等等將不會順序。這可能是一些應用程序常見的情況,實際上我嘗試了一些其他方法,例如使用System.Diagnostics.Stopwatch等更高分辨率的計時器,或將時間戳與「計數器」相結合,以保證序列一直持續到時間戳更新。但是,在測試過程中,我發現這並沒有產生明顯的差異,即使在同一毫秒的時間內生成了幾十甚至幾百個GUID。這與Jimmy Nilsson在測試COMBs期間遇到的一致

只是想知道是否有人知道數據庫內部可以分享一些關於上述觀察的燈。這是因爲數據庫服務器只是將數據存儲在內存中,並且只有在達到特定閾值時才寫入磁盤?因此,具有相同時間戳的具有非序列GUID的插入數據的重新排序通常會發生在存儲器中,因此性能損失最小。

更新: 根據我們的測試,梳GUID不能因爲它聲稱在互聯網上隨機GUID相比減少表的碎片。看來現在唯一的方法是使用SQL Server來生成順序的GUID。

+1

我認爲列出的所有文章都將*主鍵*與*聚簇索引鍵*混淆。 GUIDS可以很好地用作主鍵,尤其是在多主環境下,但不能很好地用作聚簇索引鍵(雖然「效果不好」取決於表中的其他列)。 –

+0

是的,你說得對。我們主要關心的是由於在我們的表中聚簇PK的GUID的隨機性,它會產生很多碎片。有關我的問題的任何想法在同一時間戳內的隨機GUID的性能? – windfly2006

+0

如果沒有其他列用作聚簇索引鍵,那麼我會去'newsequentialid()'(從下面的@ErikE)。 –

回答

2

您引用的文章是從2002年開始的,非常古老。只需使用newsequentialid(可在SQL Server 2005及更高版本中使用)。這可以確保您生成的每個新ID都大於前一個,從而解決索引碎片/頁面拆分問題。

但是我想提及的另一方面,那篇文章的作者掩蓋了一下,就是當你只需要4個字節時使用16個字節並不是一個好主意。假設您有一個包含500,000行(不包括聚簇列)的平均150字節的表,並且該表有3個非聚簇索引(它們在每行中重複聚簇列),每個行又分別具有4個字節,25個字節和50個行不包括聚集列的字節。

在完美100%的填充因子,其存儲要求是然後(除了以MB爲單位的所有數字,其中%):

Item Clust 50  25  4  Total 
---- ----- ----- ----- ----- ------ 
GUID 79.1 31.5 19.6 9.5 139.7 
int 73.4 25.7 13.8 3.8 116.7 
%imp 7.2% 18.4% 29.6% 60.0% 16.5% 

在僅具有一個int的4個字節列中的非聚集索引(一個常見的情況),將聚集索引切換到int使其縮小60%!這可以直接轉化爲表格上任何掃描的60%的性能改進 - 這是保守的,因爲對於較小的行,頁面拆分的發生次數會減少,並且碎片會保持更長的時間。

即使在聚集索引本身,仍然有7.2%的性能提升,這根本不算什麼。

如果你使用GUID小號在您的整個數據庫,其中有表有類似的狀況,因爲這在切換至int會產生尺寸減小16.5%,和數據庫本身在尺寸1.397萬億字節?您的整個數據庫將增加230 Gb(請參閱「總計」欄,139.7 - 116.7)。這在現實世界中轉化爲高可用性存儲的真錢。它會及時更早地調整您的磁盤採購計劃,這對您的公司的底線是有害的。

不要使用比必要的更大的數據類型。這就像加重你的車沒有理由:你支付它(如果不是在速度,然後在燃油經濟性)。

UPDATE

現在我知道你在你的客戶端代碼創建GUID,我能更清楚地看到你的問題的性質。如果你的能夠延遲創建GUID直到行插入時間,這裏有一種方法來實現這一點。

首先,設置默認爲您CustomerID列:

ALTER TABLE dbo.Customer ADD CONSTRAINT DF_Customer_CustomerID 
    DEFAULT (newsequentialid()) FOR Customer; 

現在你不必指定任何INSERT插入什麼價值爲CustomerID,和您的查詢看起來是這樣的:

DECLARE @Name varchar(100) = 'Acme Spy Devices'; 
INSERT dbo.Customer (Name) 
OUTPUT inserted.CustomerID -- a GUID 
VALUES (@Name); 

在這個非常簡單的示例中,您向Customer表插入了一個新行,並將包含剛剛創建的值的行集返回給一個查詢。

如果你想明確插入VALUES (newsequentialid(), @Name)也可以。

+0

非常感謝。我們正在使用實體框架,我們正在使用代碼來生成PK的GUID,因此我們正在尋找一些最小的代碼更改來生成代碼中的連續GUID。此時,由於代碼更改太多,我們將無法返回INT作爲PK。如果我們使用的是newsequentialid,那麼會有額外的數據庫往返行程來生成GUID,對吧? – windfly2006

+0

正確,'newsequentialid()'必須從數據庫中調用。有時代碼可以被重寫,以便在插入整個記錄之後獲得ID *,而不必在之前獲取ID - 如果是這樣,則不需要額外訪問數據庫。 – ErikE

+0

再次感謝。只是想知道,如果您不需要額外訪問數據庫,您是否可以共享一些鏈接或代碼示例。 – windfly2006

相關問題