2009-07-23 67 views
4

到目前爲止,我一直在使用C#「Guid = Guid.NewGuid();」方法來生成一個唯一的ID,該ID可以使用Linq to SQL在我的一些SQL Server數據庫表中存儲爲ID字段。 我已被告知,由於索引原因,使用GUID是一個壞主意,我應該使用自動遞增的Long來代替。請問使用長時間加速我的數據庫事務?如果是這樣,我該如何去生成Long類型的唯一ID?SQL Server - Guid VS.長

問候,

+0

「我被告知,用於索引的原因,使用GUID是一個壞主意」 - 如果你有您的身份字段上的聚集索引,GUID將會損害插入的性能。 SQL Server按照基於聚簇索引的順序存儲表。由於新的GUID是非順序的,因此插入一個新行將不得不插入到表的中間,而不是末尾,從而導致大量的IO。只要聚集索引列類型可以避免這個問題。 – adrianbanks 2009-07-23 11:50:06

+1

只是增加 - 如果GUID的主鍵,然後通過默認的GUID將被集羣 - 這可以是非叢生,但需要人工干預 – 2009-07-23 11:53:35

+0

見http://sqlblogcasts.com/blogs/martinbell/archive/2009/ 5月25日/ GUID的碎片式-SQL Server.aspx - 和http://www.dotnetrocks.com/default.aspx?showNum=455與很多關於該主題的內容播客。 – 2009-07-23 11:55:40

回答

8

兩者各有利弊,這完全取決於你如何使用它們。

馬上,如果您需要可以在多個數據庫上工作的標識符,則需要GUID。 Long有一些技巧(手動爲每個數據庫分配一個不同的種子/增量),但這些技巧不能很好地擴展。

就索引而言,如果索引是集羣的(默認情況下,主鍵是集羣的,但可以爲您的表修改),那麼Long將提供更好的插入性能,因爲表不需要在重新組織之後重新組織每個插入。

至於併發插入關心然而,長(身份)列會慢一些,然後GUID - 標識列生成需要一系列的排他鎖,以確保只有一行得到下一個序列號。在許多用戶一直插入許多行的環境中,這可能會導致性能下降。在這種情況下生成GUID更快。

存儲方面,一個GUID佔用一個長度的兩倍(8字節vs 16)。但是,如果8個字節將使一個葉片中的記錄數量有多大,並且因此在平均請求期間從磁盤中提取的葉片數量會有顯着差異,則這取決於您的行的整體大小。

3

長(大int類型的SQL Server)爲8個字節,一個GUID是16個字節,所以你減半字節的SQL Server數量已經比較做一個查找時。

若要生成一個long,請在數據庫中創建該字段時使用IDENTITY(1,1)。

所以無論是使用create table或alter table:

Field_NAME BIGINT NOT NULL PRIMARY KEY IDENTITY(1,1) 

看評論張貼的LINQ to SQL

+1

當您使用L2S將新記錄提交到數據庫時,PK未填充。它將作爲提交的一部分由L2S填充,因此如果需要,您可以在提交後從記錄對象中檢索它。 – Lazarus 2009-07-23 11:48:21

1

您可以整天辯論GUID或身份。我更喜歡數據庫以一個身份生成唯一值。如果您合併來自多個數據庫的數據,請添加另一列(以標識源數據庫,可能是tinyint或smallint)並形成複合主鍵。

如果你有一個身份去,一定要選擇正確的數據類型,根據預期鍵的數量,你會產生:

bigint - 8 Bytes - max positive value: 9,223,372,036,854,775,807 
int - 4 Bytes - max positive value:    2,147,483,647 

注意「預期鍵的數量」大於數量不同行。如果主要添加並保留行,則可能發現INT具有足夠的超過20億個唯一密鑰。我敢打賭你的桌子不會那麼大。但是,如果你有一個高容量的表,你不斷添加和刪除行,你的行數可能很低,但你會快速通過鍵。你應該做一些計算,看看它如何記錄INT 20億個密鑰。如果它不會立即使用它們,那麼請使用INT,否則將密鑰大小加倍並使用BIGINT。

3

「索引的皇后」 - Kim Tripp - 基本上說,這一切在她的索引的博客文章:

基本上,她的最佳實踐:最佳聚類密鑰應該是:

  • 獨特
  • 穩定(永遠不會改變)
  • 不斷增加

GUID的違反 「小」 和 「不斷增加」,並因此不是最佳的。

PLUS:所有集羣密鑰將被添加到每個非聚集索引中的每個條目(作爲查找實際查找數據庫中的記錄),因此您希望使它們儘可能小盡可能(INT = 4字節與GUID = 16字節)。如果你有幾億行和幾個非聚集索引,那麼在GUID上選擇一個INT或BIGINT可以產生很大的區別 - 即使只是在空間上。

馬克

1

使用GUID的時候,你需要考慮導入/導出到多個數據庫。在處理多個子關係的數據集時,Guid通常比指定IDENTITY屬性的列容易使用。這是因爲您可以從數據庫中以斷開連接的狀態在代碼中隨機生成GUID,然後一次提交所有更改。當GUID正確生成時,他們很難偶然地重複。使用標識列時,通常必須在添加子數據之前首先對父行進行初始插入並查詢其新標識。然後您必須在將它們提交到數據庫之前使用新的父身份更新所有子記錄。孫子們也是這樣,依此類推。它構建了許多似乎沒有必要和世俗的工作。通過使用不帶IDENTITY規範的隨機整數,您可以執行類似Guid的操作,但隨着時間的推移插入更多記錄,碰撞的機會將大大增加。 (Guid.NewGuid()類似於一個隨機的Int128--目前還不存在)。

我使用Byte(TinyInt),Int16(SmallInt),Int32/UInt16(Int),Int64/UInt32(BigInt)來查找不更改的小查找列表或不在多個數據庫之間複製的數據。 (權限,應用程序配置,顏色名稱等)

我想,無論您使用的是guid還是long,索引都只需要查詢一次。通常表中的其他字段的索引大於128位(例如用戶表中的用戶名)。 Guids和Integers之間的區別在於內存中索引的大小,以及時間填充和重建索引。大多數數據庫事務往往是閱讀。寫作很少。首先集中於優化數據庫讀取,因爲它們通常由未正確優化的連接表,不合適的分頁或缺少索引組成。

正如任何事情,做的最好的事情就是證明你的觀點。用兩個表創建一個測試數據庫。一個帶有整數/長整數的主鍵,另一個帶有一個guid。每個填充N百萬行。 Moniter在CRUD操作期間的每個表現(創建,讀取,更新,刪除)。你可能會發現它確實有一個性能問題,但並不重要。

服務器通常沒有調試環境和其他應用程序佔用CPU,內存盒上運行,我的硬盤驅動器(尤其是RAID)的輸入/輸出。開發環境只會給你一個性能的想法。