这种情况的最佳数据库结构是什么?

时间:2012-12-02 19:57:15

标签: sql-server database entity-framework database-design domain-model

我有一个持有房地产MLS(多重上市服务)数据的数据库。目前,我有一个表,其中包含所有列表属性(价格,地址,平方英尺等)。有几种不同的房产类型(住宅,商业,租赁,收入,土地等),每种房产类型共享大部分属性,但有一些是该房产类型所特有的。

我的问题是共享属性超过250个字段,这似乎在一个表中有太多字段。我的想法是我可以将它们分解为EAV(实体 - 属性 - 值)格式,但我已经阅读了很多关于它的不好的事情,它会使运行查询变得非常痛苦,因为可以搜索250个字段中的任何一个。如果我要去那条路线,我真的必须从EAV表中提取所有数据,按列表ID分组,将其合并到应用程序端,然后针对内存对象集合运行我的查询。这似乎也不是很有效。

我正在寻找一些有关进展方式的想法或建议。也许250+字段表是唯一可行的方法。

正如我所说,我正在使用SQL Server 2012,.NET 4.5 w / Entity Framework 5,C#,数据通过WCF服务传递给asp.net Web应用程序。

提前致谢。

3 个答案:

答案 0 :(得分:5)

让我们考虑替代方案的利弊:

所有商品+属性的一个表格:

  1. 非常宽的桌子 - 很难看到模特和架构定义和表数据
  2. 检索列表中所有数据所需的无需联接的一个查询
  3. 每个新属性都需要架构+模型更改。
  4. 如果您始终加载所有属性并且大多数项目具有大多数属性的值,则效率很高。
  5. 根据属性的示例LINQ查询:
  6. context.Listings.Where(l => l.PricePerMonthInUsd < 10e3 && l.SquareMeters >= 200)
        .ToList();
    


    所有商家信息的一个表格,一个属性类型表格和一个(列出ID +属性IDS +)值(EAV):

    1. 列表表格很窄
    2. 如果数据非常稀疏(大多数属性没有大多数项目的值),则效率高。
    3. 需要从值中获取所有数据 - 一个额外的查询(或者一个会浪费带宽的连接 - 将获取每个属性值行的基本列表数据)
    4. 不需要对新属性进行架构+模型更改
    5. 如果您希望通过代码安全地访问属性,则需要基于属性类型表生成自定义代码
    6. 根据属性的示例LINQ查询:
    7. 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();
      

      或:(比较实际数据库的性能)

      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查询介于上述两个示例之间。

      7. 根据您的具体统计数据(关于稀疏性)和需求/可维护性计划(例如,添加/更改属性类型的频率?)来考虑优缺点,并确定。

答案 1 :(得分:0)

我可能做的事情:

我首先为250个字段创建一个表,其中我有ID和FieldName,例如:

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)

这里的问题是你可能需要至少两个字段,一个用于数字,一个用于字符串。

这当然只是一个建议。

答案 2 :(得分:0)

我会创建一个listing表,其中只包含共享属性。该表将listingId作为主键。它会有一个存储列表类型的列,因此您可以知道它是否包含住宅列表,登陆列表等。

然后,对于每个子类型,创建一个额外的表。因此,您将拥有residential_listingland_listing等表格。所有这些表格的主键也是listingId。此列也是listing的外键。

如果您希望操作共享数据,可以完全从listing表执行此操作。当您对特定数据感兴趣时,您将加入特定表格。如果所有数据都存在,某些查询可能完全在特定表上运行。