让我们考虑一下替代方案的优缺点:
所有列表 + 属性的一张表:
- 非常宽的表 - 难以查看模型和模式定义以及表数据
- 一个查询不需要连接即可检索列表中的所有数据
- 需要为每个新属性更改架构 + 模型。
- 如果您始终加载所有属性并且大多数项目具有大多数属性的值,则效率很高。
- 根据属性的示例 LINQ 查询:
context.Listings.Where(l => l.PricePerMonthInUsd < 10e3 && l.SquareMeters >= 200)
.ToList();
一张表用于所有列表,一张表用于属性类型,一张表用于(列表 ID + 属性 IDS +)值 (EAV):
- 列表很窄
- 如果数据非常稀疏(大多数属性没有大多数项目的值),则效率很高
- 需要从值中获取所有数据——一个额外的查询(或者一个连接,但是,这会浪费带宽——将获取每个属性值行的基本列表数据)
- 不需要为新属性更改架构 + 模型
- 如果您希望通过代码对属性进行类型安全访问,则需要基于属性类型表的自定义代码生成
- 根据属性的示例 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();
或:(比较实际数据库的性能)
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:0..1 与列表表,而不是 1:many)
- 需要为新属性更改架构 + 模型
- 使查看模式/模型更简单 - 如果您可以将属性划分为 10 个组,您将拥有 25 个包含 11 列的表,而不是列表表上的另外 250 个
- LINQ 查询介于上述两个示例之间。
根据您的具体统计数据(关于稀疏性)和需求/可维护性计划(例如属性类型添加/更改的频率?)考虑优缺点并做出决定。