高级 EAV 模型的高效查询

Zee*_*eep 7 sql-server t-sql eav

我有点坚持如何构建一个有效的查询,该查询返回以下 EAV 结构的数据。

今天,产品表已经存在,包含 4 个固定字段。我们希望升级系统,允许无限量的附加产品字段,由每个产品的制造商定义。我们称这些附加字段为“参数”。

参数可以是以下数据类型:

  • 文本
  • 日期范围)
  • 布尔值
  • 下拉值(单个)
  • 下拉值(多个)

基于此,我创建了以下数据库模型:

数据库方案

  • Product:原始产品表,包含固定字段。
  • 参数:该表定义了所有类型的参数。目前 5:Text、Date、Boolean、Dropdown 值(单个)、Dropdown 值(多个)
  • 制造商参数:此表存储了产品制造商为其所有产品定义的参数(图中未包含制造商表)。
  • ProductParameter:这是存储所有定义参数的实际产品数据的地方。'Text' 类型的参数将其信息存储在字段 'Text' 中,'DatumBegin' 中的 'Date' 和 'Boolean' 中的 Bit/Boolean 'DatumEnd'。
  • ParameterValueListItem:此表包含单耦合和多耦合的下拉列表值的预定义值。这些是您在创建或更改产品时在下拉列表中看到的值。
  • ProductParameterValueListItem:这是为下拉列表值存储实际产品数据的地方。

我需要在 ASP.NET C# 中构建一个网页,该网页显示所有产品数据的列表,包括每个定义的参数及其对该产品的值。我需要能够通过搜索任何字段/参数来过滤列表。此列表还需要可在任何字段/参数上排序。

我尝试通过外部连接 Product - ProductParameter - ProductParametervalueListItem - ParameterValueListItem 来过滤列表,以获得包含所有数据的表结果,然后使用由 Web 应用程序构建和传递的动态 where 子句过滤该列表。这在您搜索 1 个参数时有效,但是当您开始搜索多个参数时,您会得到不正确的结果,因为每个参数在表结果中都是不同的行,并且参数 A 和 B 之间根本没有“与”匹配,因为它们不存在于同一记录(行)中。

谁能建议我如何实现这一目标?最完美的解决方案是 1 个表结果,其中包含所有数据,并且每个参数都显示为同一产品行中的一列。这是否太复杂而无法在数据库级别处理?

感谢您阅读到这里。欢迎任何建议。

Tho*_*ser 3

首先,你要设计的可能是一个非常糟糕的主意。更好的解决方案是拥有一个动态模式,您可以在其中添加新表并让应用程序了解如何查询这些表(您可以将它们放在模式中)。这很大程度上避免了使用此模型必然遇到的所有锁定和查询计划问题。CREATE TABLE偶尔运行的应用程序没有任何问题。

其次,我不确定我理解为什么你已经规范化Parameter到自己的表中?为什么不直接将其放入ManufacturerParameter表中。

第三,如果您坚持继续使用当前的模型,则有多种方法可以实现您想要的(至少如果我正确解释您的要求的话)。您可以做的就是以这样的方式编写查询,即在存在匹配时对搜索参数进行求和,然后用于HAVING过滤掉匹配的值。我假设每条记录仅填充字段Text、等之一(您可能希望通过约束来强制执行此操作BooleanDatumProductParameter

例如,要搜索一个参数具有 boolean = 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]
Run Code Online (Sandbox Code Playgroud)

如果需要列出该产品的所有参数,可以使用上面的查询模板作为嵌套查询,并回连接到ProductParameter.

可以通过维护一个计算列来优化上述查询,ProductParameter该计算列具有该表中不同数据类型的字符串表示形式。这样,上面的 OR 语句可以重写为 IN 列表(您将希望将其作为表值参数传递)。

我想重申一下,你所做的事情可能是非常错误的。如果您这样做,您很可能需要手动调整大部分查询计划 - 优化器将不再为您提供帮助。假设您没有太多查询变体,这将使您的计划缓存满。