2009-02-26 72 views
2

我們有一個使用字符串作爲主鍵的遺留數據庫。我想在遺留數據庫之上實現對象,以更好地實現一些業務邏輯併爲用戶提供更多功能。NHibernate和字符串主鍵

我讀過在表上使用字符串作爲主鍵的地方很糟糕。我想知道這是爲什麼?是否因爲區分大小寫的問題?字符集?

...爲什麼這對NHibernate特別糟糕?

...以及後續...如果字符串確實做出錯誤的主鍵,是否值得用int或GUID或類似的替換數據庫中的主鍵? (我們只有大約25-30桌參與)

回答

5

好的,我會刺傷這個。我會提供一些快速警告 - 我不是數據庫方面的專家,我的經驗是使用Hibernate(Java)而不是NHibernate,但是在這裏。

我認爲主鍵作爲字符串的問題與用於在數據庫中表示它們的SQL數據類型有關。由於主鍵在插入,查詢等操作中一直在使用,因此數據庫引擎必須花費大量時間比較主鍵。如果您使用的是數字,則這些數據只會以字節的形式存儲起來,這些字符串是電腦擅長快速處理的字節。只要你開始使用字符串,這些操作的成本(主要是比較)顯着增加。即使數據庫引擎使用真正整潔的策略來比較密鑰,但將字節作爲字節而不是字符串進行比較總是會更快。

然而,在現代硬件上,這已經不像以前那樣成爲一個問題了,而且使用索引時問題幾乎消失了。

我不確定爲什麼在Hibernate(和NHibernate)中這是非常糟糕的,但以我的經驗,因爲我的應用程序有一個複雜的對象圖,經常有其他持久對象的引用,通常是列表或這些引用都是使用另一個對象的ID存儲的,而且由於我有用於級聯保存,提取等等的規則,這就意味着主鍵始終處於使用狀態。休眠 - 我很喜歡 - 往往完全按照它的要求來做,有時候人們(特別是我!)會告訴它做真正愚蠢的事情。因此,即使看似簡單的更新或查詢最終也會生成相當複雜的SQL。

因此 - 總結 - 作爲主鍵的字符串由於對它們進行簡單操作的代價而不好,並且使用Hibernate可能會放大這一點。但在實踐中,現代數據庫引擎有許多整潔的策略來確保性能降低並不差。 (Postgres - 大概是其他人 - 默認情況下會爲主鍵創建索引)

爲了您的後續工作 - 是否應該更換密鑰?那麼,這取決於你的應用程序的性能。如果性能至關重要,那麼對於高容量且密集型的應用來說,這可能是一個好主意,否則可能只有最小的好處,而不得不花費時間更換所有表格。你可以期望得到更好的結果,改進你使用NHibernate的策略(即獲取策略和級聯保存等)。

1

Andy K似乎暗示字符串不是以字節存儲的。這很有趣!事實上,這一切都取決於字符串PK的長度和您使用的排序規則。它可能比bigint或int身份更快,幾乎肯定會比Guid更快。如果這些字符串是你必須要搜索的東西,那麼無論如何你都需要一個索引(或許甚至是聚集索引),所以爲什麼不讓它們成爲PK呢?

0

使用字符串或字符將大量的accidental complexity添加到您的系統。考慮以下問題:

  • 如何處理區分大小寫;
  • 如何處理填充。 NHibernate允許你插入一個較短的字符串,並且數據庫會靜靜地向它添加填充,但它不會反映在持久實體中。嘗試使用內存中的ID再次獲取實體將返回null;
  • 如何處理編碼問題。 C#使用unicode字符串,您的數據庫不會遷移。你能否告訴我們如何處理轉換?我不這麼認爲。
  • 合成整數密鑰可以由大多數數據庫自動生成,無需額外的工作。對於字符串,您最有可能「手工」創建它們。除非您將它們隱藏在工廠之後(DDD意義上),否則結果代碼會混亂您的域模型。

雖然通過安迪ķ提到的性能開銷,因爲索引的減少,還是有很多時候你做內存ID comparisions(哈希地圖?)和DB優化不會有應用。

我一直在使用一個遺留數據庫有字符串主鍵和根本沒有外鍵的項目。我們不允許使用舊的模式,因爲傳統應用程序依賴於它的每個小方面。我覺得字符串主鍵比一些缺少的外鍵傷害了一致性,因爲NHibernate比較優雅地處理後者。