3

我有一個擁有房地產MLS(多房產服務)數據的數據庫。目前,我擁有一個包含所有列表屬性(價格,地址,平方英尺等)的表格。有幾種不同的房產類型(住宅,商業,租賃,收入,土地等),每種房產類型都具有大部分屬性,但有一些屬性類型是唯一的。什麼是這種情況下最好的數據庫結構?

我的問題是共享的屬性超過250場,這似乎是太多領域有一個表。我的想法是我可以將它們分解成EAV(Entity-Attribute-Value)格式,但我已經閱讀了許多有關這方面的不好的事情,並且它會使運行查詢成爲真正的痛苦,因爲可以搜索250個字段中的任何一個。如果我要走這條路線,我必須從EAV表中抽出所有數據,按列表ID分組,然後將它合併到應用程序端,然後針對內存對象集合運行我的查詢。這似乎也不是很有效。

我找一些想法或建議,其方式進行。也許250+字段表是唯一可行的方法。

正如一個音符,我使用的是SQL Server 2012中,.NET 4.5瓦特/實體框架5,C#和數據通過WCF服務傳遞給asp.net web應用程序。

在此先感謝。

+0

哎呀,對不起,我的意思是EAV(實體 - 屬性 - 值),我會更新我的問題。 – Ricketts

+0

重新標記 - 問題與C#無關 - .NET語言不可知。重要的考慮事項是SQL Server優化,實體框架優化。此外,ASP.NET WCF並不相關,因爲您不必在EF和WCF中使用相同的實體(如果需要,您可以使用映射)。 –

回答

5

讓我們考慮的備選方案的利弊:

其中的所有目錄+表屬性:

  1. 很寬表 - 很難查看模型&模式定義和表數據
  2. 一個查詢沒有聯接要求中檢索關於上市(S)的所有數據
  3. 需要爲每個新的屬性架構+模式的變革。
  4. 有效的,如果你總是加載所有的屬性和多數項目已大部分屬性的值。根據屬性
  5. 例LINQ查詢:
context.Listings.Where(l => l.PricePerMonthInUsd < 10e3 && l.SquareMeters >= 200) 
    .ToList(); 


一個的所有目錄表中,屬性類型一個表,一個用於(清單的ID +屬性IDS +)值(EAV):

  1. 清單表是窄
  2. 有效的,如果數據非常稀疏的(大多數屬性不具備莫值st items)
  3. 需要從值中提取所有數據 - 一個額外的查詢(或一個連接,但會浪費帶寬 - 將獲取每個屬性值行的基本列表數據)
  4. 不需要模式+模型更改新屬性
  5. 如果你想類型安全的訪問通過代碼的屬性,你會基於屬性類型的表需要自定義代碼生成
  6. 例LINQ查詢根據屬性:
var listingIds = context.AttributeValues.Where(v => 
        v.AttributeTypeId == PricePerMonthInUsdId && v < 10e3) 
       .Select(v => v.ListingId) 
       .Intersection(context.AttributeVales.Where(v => 
        v.AttributeTypeId == SquareMetersId && v.Value >= 200) 
       .Select(v => v.ListingId)).ToList(); 

或(比較實際DB的性能)

var listingIds = context.AttributeValues.Where(v => 
        v.AttributeTypeId == PricePerMonthInUsdId && v < 10e3) 
       .Select(v => v.ListingId).ToList(); 

listingIds = context.AttributeVales.Where(v => 
       listingIds.Contains(v.LisingId) 
       && v.AttributeTypeId == SquareMetersId 
       && v.Value >= 200) 
      .Select(v => v.ListingId).ToList(); 

然後:

var listings = context.Listings.Where(l => listingIds.Contains(l.ListingId)).ToList(); 


妥協的選擇 - 一個表中的所有目錄和每個屬性,包括值的組中的一個表(假設你可以將屬性劃分爲組):

  1. 多箇中等寬度表
  2. 如果每組數據稀疏(例如,與花園有關的屬性在沒有花園的情況下全部爲空,因此您不需要爲花園相關表添加行)
  3. 需要一個包含多個連接的查詢(帶寬不會浪費在連接中,因爲組表爲1:0 .1帶有列表表格,而不是1:很多)
  4. 要求對新屬性進行模式+模型更改
  5. 查看模式/模型更簡單 - 如果您可以將屬性劃分爲10個組,則會有25個表在列表中有11列而不是另外250列表
  6. LINQ查詢位於上述兩個示例之間的某處。


根據您的具體統計數據(關於稀疏),並要求/維護計劃(例如添加多久是屬性類型/改變了嗎?),並決定考慮利弊。

+0

我可以告訴你,由於進入列表的代理人留下的空白,許多字段將是空白的。並非所有字段都將被拉取所有查詢。用戶可以控制哪些字段被拉出。爲一個用戶拉取的字段與爲其他用戶拉取的字段不同。此外,由於數據來自MLS直接,他們經常更改,添加和刪除字段(我無法控制)。有人說,如果是你,你會親自採取上述哪一種方法?我會認爲EAV方法,但是我讀過的關於它的不好的事情讓我覺得不然。 – Ricketts

+0

@Ricketts EAV方法非常靈活,我已經看到它的工作。由於大多數都是空白的(除非你迫使代理商填補它們),我認爲EAV方法更適合。 –

+0

我建議每個數據類型使用一個值列,但不是所有的nvarchar而不是變體列(EF不支持)。如果您需要詳細說明如何使用EF進行此項工作,請提出有關此問題的問題,我將在明天發佈答案(將鏈接留爲評論)。 –

0

我可能會做:

我先創建一個表爲250場,在那裏我有ID和字段名,例如:

price -> 1 
address -> 2 
sqft -> 3 

此表也將硬編碼在我的代碼作爲枚舉和用於查詢。

然後,在主臺我有兩個字段一起,一個字段ID的從上面的表中獲取它的類型,以及它的第二值,例如

Line1: 122(map id), 1 (for price), 100 (the actually price) 
Line2: 122(map id), 2 (for address), "where is it" 
Line3: 122(map id), 3 (for sqft), 10 (sqft) 

這裏的問題是你可能至少需要兩個字段,一個用於數字,另一個用於字符串。

這僅僅是一個當然的建議。

+0

這是問題中提到的EAV模式。 –

+0

所以你會選擇EAV風格的路線。可以說,用戶需要列表價格介於100k到200k之間,3+臥室,2000+平方英尺和郵政編碼12345之間的價格。在db端運行該查詢將非常困難。所以我需要拉取所有記錄,通過在內存對象中列出id來分組,然後在該對象集合上運行查詢。這對性能或者內存甚至可以處理數千甚至數十萬條記錄會如何呢? – Ricketts

+0

這個問題不會寫這樣的查詢。沒有現代的數據庫管理系統會在數百萬行表上運行查詢時遇到問題 - **正確編制索引時**。 EAV的困難之處在於爲「價值」列編制索引。該列將具有非常不同數據類型,字符,數字,日期等的數據。因此,它可能必須是'VARCHAR'數據類型。這意味着,你不能輕易地爲(數量)價格或日期等索引。 –

0

我會創建一個只包含共享屬性的listing表。該表格將具有listingId作爲主鍵。它將有一列存儲列表類型,以便知道它是住宅列表,登陸列表等。

然後,爲每個子類型創建一個額外的表。所以你應該有residential_listing,land_listing等的表格。所有這些表格的主鍵也是listingId。此列也是listing的外鍵。

當您希望對共享數據進行操作時,您可以完全從listing表中完成此操作。當您對特定數據感興趣時,您將加入特定表格。如果所有數據都在那裏,某些查詢可能完全在特定的表上運行。

+0

使用組合而不是繼承(相同的模式,與實體的不同映射)可能會更好,因爲列表可以同時具有多種類型的屬性。無論如何,這與我提出的第三個選項是一樣的。 –

+0

@DannyVarod是 - 取決於哪些東西具有哪些屬性。 –

相關問題