2008-11-04 65 views
17

我目前正在通過查找表生成主鍵的數據庫,其中包含表名列表和最後使用的主鍵。一個存儲過程增加這個值並在返回到調用'insert'SP之前檢查它是唯一的。不使用主鍵的自動遞增號碼的原因

使用這種方法(或只是生成一個GUID)而不是僅僅使用身份/自動編號有什麼好處?

我不是在談論主鍵,它實際上意味着像ISBN或產品代碼,只是唯一的標識符。

謝謝。

回答

27

自動生成的ID會在您使用複製的情況下導致問題(因爲我確信您找到的技術可以!)。在這些情況下,我通常選擇一個GUID。

如果你不太可能使用複製,那麼一個自動遞增的PK很可能會工作得很好。

+0

你能舉一個複製的例子嗎?我們不能在複製時使用自動生成的ID的身份插入嗎? – ivorykoder 2013-07-18 16:28:51

+0

@ivorykoder如果兩個數據庫都生成一個新行(並因此生成一個新ID),然後嘗試同步,則表中的兩個不同行將具有不同的PK,這會有衝突。如果您使用GUID,PK實際上保證是唯一的。 – Matthew 2016-10-31 12:02:19

6

遞增的過程方法必須是線程安全的。如果不是,您可能無法獲得唯一的號碼。此外,它必須快速,否則將是一個應用程序瓶頸。內置功能已考慮到這兩個因素。

2

一個好處是它可以讓數據庫/ SQL更加跨平臺。在SQL Server,Oracle等上的SQL可以完全相同...

6

對於客戶端來說,預先分配一大堆ID來執行批量插入而不必更新其本地對象與插入的ID一起使用。然後是Galwegian所提到的整個複製問題。

3

使用唯一標識符將允許您合併來自兩個不同數據庫的數據。

也許你有一個應用程序收集多個數據庫中的數據,然後在一天中的不同時間與主數據庫「同步」。在這種情況下,您不必擔心主鍵衝突。

或者,在實際創建之前,您可能想知道記錄的ID是什麼。

1

我能想到的唯一理由是,該代碼被寫入之前sequences被髮明和代碼忘了追趕;)

+0

對。我們最早的應用程序之一的數據庫採用了本地化的方法,使用序列表(基本上是描述的),因爲MySQL當時不支持它們(或者可能是錯誤的)。這些表格依然存在,但我們現在一直在使用真實的東西。 – MBCook 2008-11-04 17:24:44

1

我寧願使用GUID大部分場景在這篇文章的目前的方法對我來說意義重大(複製是可能的)。如果複製是個問題,那麼這樣一個存儲過程必須意識到其他服務器必須鏈接以確保密鑰的唯一性,這會使其非常脆弱,並且可能是一種糟糕的方式。
我使用不是自動遞增身份的整數主鍵的一種情況是,強制外鍵約束的很少更改的查找表的情況,這些查詢表在數據消耗應用程序中將具有相應的枚舉。在這種情況下,我想確保在開發和部署之間enum映射是正確的,特別是如果將有多個prod服務器。

0

這樣做的唯一真正原因是數據庫不可知(如果不同的數據庫版本使用不同的自動編號技術)。

這裏提到的另一個問題是能夠在多個地方創建記錄(如在中心辦公室以及在旅行用戶的筆記本電腦上)。不過,在這種情況下,您可能需要類似於每個安裝所獨有的「站點代碼」,而每個安裝都以每個ID爲前綴。

1

另一個潛在的原因是你故意要隨機密鑰。例如,如果您不想讓多餘的瀏覽器瀏覽數據庫中的每個項目,但是這並不足以保證實際的身份驗證安全措施,那麼這可能是可取的。

17

使用自動編號沒有任何內在的錯誤,但有幾個理由不這樣做。正如dacracot提到的那樣,推出自己的解決方案並不是最好的主意。讓我解釋。

不使用每個表上的自動編號的第一個原因是您可能最終合併來自多個表的記錄。假設您有銷售訂單表和其他類型的訂單表,並且您決定提取一些常見數據並使用多個表繼承。擁有全局唯一的主鍵很不錯。這與bobwienholt關於合併數據庫的說法類似,但它可能發生在數據庫中。其次,其他數據庫不使用這種範式,其他範例如Oracle的序列更好。幸運的是,可以使用SQL Server模擬Oracle序列。一種方法是爲整個數據庫創建一個名爲MainSequence的AutoNumber表,或者其他的。數據庫中沒有其他表將使用自動編號,但任何需要自動生成主鍵的人都將使用MainSequence來獲取它。通過這種方式,您可以獲得所有內置的性能,鎖定,線程安全性等等,而不需要自己構建它。

另一種方法是使用GUID作爲主鍵,但我不建議這樣做,因爲即使您確定人類(甚至是開發人員)永遠不會讀取它們,也可能有人會這樣做,而且很難。更重要的是,在T-SQL中隱式地轉換爲整型,但隱式轉換爲GUID可能會遇到很多麻煩。基本上它們不方便。

在構建一個新的系統時,我建議使用專用的表來生成主鍵(就像Oracle序列一樣)。對於現有的數據庫,我不會無法改變它。

10

CodingHorror

GUID優點

  • 獨特的橫跨每個表,每個數據庫,每個服務器
  • 從不同的數據庫允許的記錄很容易合併
  • 允許跨多個數據庫易於分發服務器
  • 您可以在任何地方生成身份證,而不必往返數據庫
  • 大多數複製方案需要GUID列反正

GUID缺點

  • 它比傳統的4個字節的索引值大的高達4倍;這會產生嚴重的性能和存儲的影響,如果你不小心
  • 繁瑣的調試(其中userid =「{BAE7DF4-DDF-3RG-5TY3E3RF456AS10}」)
  • 生成的GUID應該是最佳性能部分的順序(例如SQL 2005上的newsequentialid()),並啓用聚簇索引的使用

本文提供了許多關於在GUID與自動遞增上做出決定的良好外部鏈接。如果可以,我用GUID去。

0

使用GUID主鍵而不是自動遞增GUID主鍵的一個有益的副作用是您可以在客戶端爲新行分配PK值(實際上,您必須在複製方案中執行此操作) ,省去了檢索剛添加到服務器上的行的PK的麻煩。

GUID PK的一個缺點是GUID字段上的連接速度較慢(除非最近發生了變化)。使用GUID的另一個好處是,嘗試向非技術經理解釋爲什麼GUID碰撞是不太可能的,這很有趣。

0

我自動遞增鍵的主要問題是它們缺少任何含義。

對於某些字段提供唯一性(無論是單獨還是與另一個組合)的表格,我會選擇使用它。

3

我有自動遞增鍵主要問題是,他們沒有任何意義

這是一個主鍵的要求,在我的腦海裏 - 有沒有其他原因存在除了識別記錄之外。如果它沒有現實世界的意義,那麼改變就沒有現實世界的理由。一般來說,您不希望主鍵發生更改,因爲您必須搜索 - 更換整個數據庫或更糟糕。我對於我所認爲的那些獨特而不變的事情感到驚訝,這些事情在數年後纔出現。

0

Galwegian的回答不一定是正確的。

使用MySQL,您可以爲每個數據庫實例設置一個鍵偏移量。如果你把這個與足夠大的增量結合起來,它會很好。我相信其他廠商會有類似的設置。

假設我們有2個我們想要複製的數據庫。我們可以通過以下方式進行設置。

increment = 2 
db1 - offset = 1 
db2 - offset = 2 

這意味着

DB1將具有鍵1,3,5,7 ....

DB2將有鍵2,4,6,8 ....

因此,我們不會有關於插入的關鍵衝突。

2

這裏是有自動遞增的整數作爲鑰匙的東西:你必須有張貼記錄你訪問它之前

。這意味着,除非您發佈記錄,否則不能準備將存儲在另一個表中的相關記錄,或者爲什麼訪問新記錄的唯一性可能會有幫助的其他可能原因中的任何一個ID,之後發佈。

以上是我決定的因素,無論是採用一種方法還是其他方法。