2010-05-26 103 views
16

我們正在開始一個新項目,我們需要將產品和許多產品屬性存儲在數據庫中。技術堆棧是用於數據訪問的MS SQL 2008和實體框架4.0/LINQ。在SQL Server中存儲(產品)屬性的最佳模式

產品(和產品表)非常簡單(SKU,製造商,價格等)。但是,每個產品都有很多屬性可以存儲(比如工業小部件)。這些範圍可能從顏色到認證(s)到管道尺寸。每個產品可能具有不同的屬性,有些可能具有相同屬性的倍數(例如:認證)。

當前的建議是,我們基本上會有一個名稱/值對錶,並將FK返回到每行中的產品ID。

屬性表的例子可能是這樣的:

ProdID  AttributeName  AttributeValue 
123  Color    Blue 
123  FittingSize  1.25 
123  Certification  AS1111 
123  Certification  EE2212 
123  Certification  FM.3 
456  Pipe    11 
678  Color    Red 
999  Certification  AE1111 
... 

注:屬性名稱可能會來自查找表或枚舉。

所以這裏的主要問題是:這是做這種事情的最佳模式?表演將如何?查詢將基於產品和屬性表的JOIN,並且通常需要許多WHERE來過濾特定屬性 - 最常見的搜索將基於一組已知/期望屬性來查找產品。

如果有人對此類數據有任何建議或更好的模式,請告訴我。

謝謝! -Ed

回答

15

您即將重新發明可怕的EAV模型實體屬性值。這是由於各種原因在現實生活中遇到問題而臭名昭着,其中許多由戴夫的答案所覆蓋。

幸運的是,SQL客戶諮詢團隊(SQLCAT)的主題爲白皮書 Best Practices for Semantic Data Modeling for Performance and Scalability。我強烈推薦這篇論文。不幸的是,它不提供靈丹妙藥,曲奇刀解決方案,因爲問題沒有解決辦法。相反,你將學會如何找到一個固定的可查詢模式和靈活的EAV結構,對於您的特定情況下,工作的平衡之間的平衡:

語義數據模型可以很複雜 ,直到語義數據庫 通常是可用的,挑戰 仍然在每個 應用程序的純對象模型和純關係模型之間找到最佳平衡 。成功的關鍵是要了解 的問題,對 問題做出必要的緩解,然後進行測試,測試和測試。 可擴展性測試是一個關鍵的 成功因素,如果你打算 找到最佳設計。

+1

+1,如果僅僅是因爲鏈接的文件比迄今爲止寫在這個頁面上的任何內容更有用。 – 2010-05-26 12:50:18

+0

這篇文章有所幫助,並給了我們很多想法。謝謝! – EdH 2010-05-27 19:27:04

13

這將是一對夫婦的原因問題:

  • 你的實體的查詢將是更難寫。將這些查詢的結果轉換爲類似於ViewModel的內容時,將會非常痛苦,因爲它將涉及每個產品的支點。

  • 當需要閱讀某些類型的數據時,瞭解數據類型將會變得困難。你打算把它存儲爲字符串嗎?例如,DateTimes保存的數據比默認的.ToString()實現寫入字符串更多。如果你嘗試存儲浮點值,你也會遇到問題。

  • 您的對象的數據完整性存在風險。在這個「桶o數據」中將會有一種誘惑,即將屬性應該只是主要產品表的屬性。也許設計的初衷會是半理智的,但我保證,在一定的時間過後,人們會開始將物品放在包裏。那麼使用這種鬆散定義的結構來保持對象的完整性將非常困難。

  • 您的索引很可能不是最理想的。再想一想應該在你的產品表上的財產。現在,您不得不在一個列上編制索引,而只能在「類型」表上創建一個潛在的非常大的組合索引。

  • 既然你顯然打算扔掉適當的數據類型和使用字符串,範圍查詢的數值數據的表現可能會很差。

  • 你的桌子會得到很大的,減緩備份和查詢。而不是一個整數是4字節,你將不得不爲任何大小的整數存儲更多。

更好地使用「IS-A」關係以更傳統的方式對錶格進行歸一化。例如,您可能有Pipes,它是一種產品類型,但具有更多屬性。你可能有火爐,這是一種產品,但仍然有更多屬性。

如果您確實擁有通用數據庫以及其他各種不受數據完整性規則約束的屬性,那麼您可能會考慮將數據存儲在XML列中。除非我更瞭解您的業務,否則很難告訴您正確的設計選擇。

IMO這是一個設計反模式。這個想法的警笛歌曲吸引了很多開發者進入一個無法維護的應用程序的岩石。

+0

感謝您花時間留下詳細回覆。我們同意這個計劃有很多問題,但你提出的(半)解決方案也不會有幫助。單個SKU可以有數百個屬性。認證和其他屬性按月進行。我不確定我們如何能夠用傳統的IS-A關係來管理這個模式。我們需要多個專門負責此應用/架構的人員才能每週管理SKU更改。 – EdH 2010-05-26 02:36:45

+1

這就是爲什麼你應該考慮使用XML列。您可以在數據庫中使用EAV獲取某些屬性,但不要期望搜索和報告快速或直觀。您真的需要了解如何/如果這些屬性將被搜索,以及每個屬性在應用程序的生命週期中是如何進行的。這種基本的業務分析會告訴你每個屬性的屬性。 – 2010-05-26 10:35:14

1

不是創建一個名稱 - 值表,而是創建包含所有常用屬性的常用Product表結構,併爲各個產品的屬性添加一個XML列。

我以前使用過這種結構,它工作得很好。

正如@Dave Markle所說,名稱 - 價值的方法會導致一個痛苦的世界。

+0

如何有效地查詢特定屬性的XML? – EdH 2010-05-26 02:37:44

+1

如果明智地創建xml索引,性能將會很好。 – 2010-05-26 02:52:08

2

總之,你不能走全部路線。如果你像你的例子一樣使用EAV,你將會遇到無數的問題,如其他海報所概述的問題,其中最重要的是性能和數據完整性。讓我重申一下,使用EAV作爲解決方案的核心將在您進行報告和分析時失敗。然而,正如你所說,你可能有數百個定期變化的屬性。

IMO的解決方案是一種混合型。對於通用屬性,請使用列/標準模式。對於其他任意屬性,請使用EAV。但是,使用EAV數據的規則是,在任何情況下,永遠不可以編寫包含對屬性進行排序或過濾的查詢。即,你永遠不能寫Where AttributeName = 'Foo'。該架構的EAV部分代表一個僅用於跟蹤目的的數據包。事實上,我看到很多人通過使用Xml來實現這個解決方案,用於EAV部分。在某人想要搜索,過濾,排序或在報告中的特定位置放置EAV值時,必須將該屬性提升到產品表中的頂級列。

這種混合方法的關鍵是紀律。這似乎很簡單,可以添加一個過濾器,將某個屬性排序或放入報告中的某個特定位置,特別是當您受到管理層的壓力時。你必須抵制這種誘惑。一旦你走上黑暗的道路......如果你認爲你的開發團隊不能保持這種紀律,那麼我就不會使用EAV。正如我之前提到的那樣,EAV就像藥物一樣:數量少,在正確的環境下使用它們可能是有益的。太多會殺了你。

4

我知道這是一個古老的 - 但有可能是其他讀者......

我所見過的平衡EAV的屬性建模方法。那麼 - 它仍然是EAV。 「EAV就像毒品」是非常真實的。那麼,再一次思考 - 讓我們變得更具攻擊性: 我仍然喜歡supertype apporach,在這裏很多表使用密鑰生成器中的相同主鍵。讓我們重複使用這一個。那麼爲每組屬性創建一個新表格 - 所有這些屬性都來自同一個密鑰生成器的主要表格?例如。您將擁有一個帶「顏色,管道」字段,另一個表「裝配,管道」等的表格。無論如何,「屬性波動性」的要求尖叫着仔細(自動)維護的數據字典。

此方法已完全標準化並且可以完全自動化。你可以通過散列屬性名稱簇來支持檢查特定屬性集是否已經物化爲表,例如。 crc32(lower('color〜fittingsize〜pipe')),其中屬性名稱需要按字母順序排序。當然這需要在數據字典中包含哈希。基於數據字典,可以搜索每個對象(使用'UNION'),特別是如果數據字典本身是一個表。將數據字典作爲表還允許使用其主鍵(代理鍵)作爲唯一表名的基礎,最終得到像'attributes1','attributes2'這樣的表......現在的大多數數據庫都支持數十億個表 - 所以我們在這方面也有所節省。你甚至可以擁有一個具有非常常見屬性的產品catalouge,它引用擴展屬性表。

一個公開的問題是1:n數據集。恐怕你需要在單獨的表格中整理出來。但是,這非常依賴於您的數據表示和查詢策略。它們是否總是以附在產品上的逗號分隔的字符串形式呈現,或者您是否想要例如。能夠查詢某個認證的所有產品嗎?

在您採用這種方法之前,請考慮這一點:它指的是僅在數量和質量上具有非常高的屬性波動性的用例。此外,它是預設的,您無法知道解決方案創建時的大部分屬性。因此,不要在可以預先建立屬性的模型中討論這個問題,這可以使您更好地平衡權衡。

相關問題