Sql-Server

始終將單個整數列作為主鍵有什麼缺點?

  • May 7, 2020

在我正在處理的一個 Web 應用程序中,所有數據庫操作都使用一些在實體框架 ORM 上定義的通用儲存庫進行抽象。

但是,為了對通用儲存庫進行簡單設計,所有涉及的表都必須定義一個唯一的整數(Int32在 C# 中,int在 SQL 中)。直到現在,這一直是桌遊的PK,也是IDENTITY

外鍵被大量使用,它們引用這些整數列。它們對於一致性和 ORM 生成導航屬性都是必需的。

應用層通常執行以下操作:

  • 從表中載入初始數據(*) -SELECT * FROM table
  • 更新-UPDATE table SET Col1 = Val1 WHERE Id = IdVal
  • 刪除-DELETE FROM table WHERE Id = IdVal
  • 插入-INSERT INTO table (cols) VALUES (...)

不太頻繁的操作:

  • 批量插入-BULK INSERT ... into table所有數據載入後跟 (*)(檢索生成的標識符)
  • 批量刪除- 這是一個正常的刪除操作,但從 ORM 的角度來看是“龐大的”:DELETE FROM table where OtherThanIdCol = SomeValue
  • 批量更新- 這是一個正常的更新操作,但從 ORM 的角度來看是“龐大的”:UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue

*所有小表都在應用程序級別記憶體,幾乎所有SELECTs都不會到達數據庫。一個典型的模式是初始載入和大量的INSERTs、UPDATEs 和DELETEs。

根據目前的應用程序使用情況,在任何表中達到 100M 記錄的可能性非常小。

問題: 從 DBA 的角度來看,有這個表設計限制我會遇到重大問題嗎?

$$ EDIT $$

在閱讀了答案(感謝您的回饋)和參考文章後,我覺得我必須添加更多細節:

  1. 目前應用程序細節- 我沒有提及目前的 Web 應用程序,因為我想了解該模型是否也可以用於其他應用程序。但是,我的特殊情況是從 DWH 中提取大量元數據的應用程序。源數據非常混亂(以一種奇怪的方式去規範化,有一些不一致,在許多情況下沒有自然標識符等),我的應用程序正在生成清晰的分離實體。此外,還會顯示許多生成的標識符 ( IDENTITY),以便使用者可以將它們用作業務密鑰。除了大量的程式碼重構之外,這還排除了 GUID 的使用

  2. “它們不應該是唯一標識一行的唯一方法”(Aaron Bertrand♦)——這是一個非常好的建議。我所有的表還定義了一個 UNIQUE CONSTRAINT 以確保不允許業務重複。

  3. 前端應用驅動設計與數據庫驅動設計- 設計選擇是由這些因素引起的

  4. 實體框架限制- 允許多列 PK,但它們的值不能更新

  5. 自定義限制- 具有單個整數鍵大大簡化了資料結構和非 SQL 程式碼。例如:所有值列表都有一個整數鍵和一個顯示值。更重要的是,它保證任何標記為記憶體的表都能夠放入Unique int key -> value映射中。

  6. 複雜的選擇查詢——這幾乎不會發生,因為所有小(< 20-30K 記錄)表數據都在應用程序級別記憶體。這使得編寫應用程式碼時的生活有點困難(更難編寫 LINQ),但數據庫受到的影響要好得多:

  7. 列表視圖- 不會SELECT在載入時生成查詢(所有內容都被記憶體)或如下所示的查詢:

SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)

有其他必需的值都是通過記憶體查找 (O(1)) 獲取的,因此不會生成複雜的查詢。
 **編輯視圖**- 將生成`SELECT`如下語句:
LECT allcolumns FROM BigTable WHERE PKId = value1


(所有過濾器和值都是`int`s)

除了額外的磁碟空間(以及記憶體使用和 I/O)之外,即使對不需要 IDENTITY 列的表(不需要 IDENTITY 列的表的範例)添加 IDENTITY 列也沒有任何害處是一個簡單的聯結表,例如將使用者映射到他/她的權限)。

我反對在 2010 年的部落格文章中盲目地將它們添加到每個表中:

但是代理鍵確實有有效的案例——請注意不要假設它們保證唯一性(這有時是它們被添加的原因——它們不應該是唯一標識行的***唯一方法)。***如果您需要使用 ORM 框架,並且您的 ORM 框架需要單列整數鍵,即使您的實際鍵不是整數,也不是單列,或者兩者都不是,請確保定義唯一約束/索引也可以用於您的真正鑰匙。

引用自:https://dba.stackexchange.com/questions/163154