Sql-Server

高級 EAV 模型的高效查詢

  • June 28, 2014

我對如何建構一個返回以下 EAV 結構的數據的有效查詢有點困惑。

今天,已經存在一個產品表,其中包含 4 個固定欄位。我們希望升級系統,允許無限量的附加產品欄位,由每個產品的製造商定義。我們將這些附加欄位稱為“參數”。

參數可以是以下數據類型:

  • 文本
  • 日期範圍)
  • 布爾值
  • 下拉值(單個)
  • 下拉值(多個)

基於此,我創建了以下數據庫模型:

數據庫方案 :

  • Product:原始產品表,包含固定欄位。
  • 參數:此表定義了所有類型的參數。目前5:文本、日期、布爾值、下拉值(單個)、下拉值(多個)
  • ManufacturerParameter:此表儲存產品製造商為他的所有產品定義的參數(圖中未包含製造商表)。
  • ProductParameter:這是儲存所有已定義參數的實際產品數據的位置。“Text”類型的參數將其資訊儲存在“Text”欄位中,“Date”儲存在“DatumBegin”和“DatumEnd”,Bit/Boolean儲存在“Boolean”。
  • ParameterValueListItem:此表包含單耦合和多耦合的下拉列表值的預定義值。這些是您在創建或更改產品時在下拉列表中看到的值。
  • ProductParameterValueListItem:這是為 Dropdownlist 值儲存實際產品數據的位置。

我需要在 ASP.NET C# 中建構一個網頁,其中顯示所有產品數據的列表,包括每個定義的參數及其對該產品的值。我需要能夠通過搜尋任何欄位/參數來過濾列表。該列表還需要可按任何欄位/參數進行排序。

我嘗試通過外部連接 Product - ProductParameter - ProductParametervalueListItem - ParameterValueListItem 來過濾列表,以獲得包含所有數據的表結果,然後使用動態 where 子句過濾該列表,該子句由 Web 應用程序建構和傳遞。這在您搜尋 1 個參數時有效,但是當您開始搜尋多個參數時,您會得到不正確的結果,因為每個參數是表結果中的不同行,並且參數 A 和 B 之間根本沒有“AND”匹配,因為它們不存在於同一記錄(行)中。

誰能建議我如何實現這一目標?最完美的解決方案是 1 個表格結果,其中包含所有數據,並且每個參數在同一產品行中顯示為一列。這是否太複雜而無法在數據庫級別處理?

感謝您閱讀本文。歡迎任何建議。

首先,你要設計的可能是一個非常糟糕的主意。一個更好的解決方案是擁有一個動態模式,您可以在其中添加新表並讓應用程序了解如何查詢這些表(您可以將它們放在一個模式中)。這在很大程度上避免了使用此模型必然會遇到的所有鎖定和查詢計劃問題。不時執行的應用程序沒有任何問題CREATE TABLE

其次,我不確定我是否理解您為什麼要規範化Parameter到自己的表中?為什麼不直接把它放到ManufacturerParameter表中。

第三,如果您堅持使用目前模型,則有一些方法可以實現您想要的(至少如果我正確解釋了您的要求)。您可以做的是以這樣一種方式編寫您的查詢,當有匹配時它是對搜尋參數的總結,然後用於HAVING過濾掉匹配的值。我假設每條記錄僅填充一個欄位Text,Boolean等(您可能希望通過約束來強制執行此操作)Datum``ProductParameter

例如,要搜尋一個參數為 bolean = true 且其他參數為 text = ‘abc’ 的所有產品,您可以執行以下操作:

SELECT P.Name
FROM Product P
JOIN ProductParameter PP
WHERE P.ID = Foo
 AND PP.Boolean = 1 OR PP.Text = 'abc'  ... /* For each filter */
GROUP BY P.Name /* And any other things you want out of product */
HAVING COUNT(*) >= [Number of where clauses]

如果需要列出該產品的所有參數,可以使用上面的查詢模板作為嵌套查詢,並回連接到ProductParameter.

可以通過維護一個計算列來優化上述查詢,該列ProductParameter具有該表中不同數據類型的字元串表示。這樣,上述 OR 語句可以重寫為 IN 列表(您將希望將其作為表值參數傳遞)。

我想重申一下,您所做的可能是非常錯誤的。如果您這樣做,您很可能需要手動調整大部分查詢計劃 - 優化器將不再幫助您。這是假設您沒有太多的查詢變體,這將使您的計劃記憶體完全執行。

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