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是 - 取决于哪些东西具有哪些属性。 –

相关问题