使用用户定义的键/值对将自定义查询映射到分层实体的“规范”方法

时间:2016-03-26 19:10:21

标签: sql key-value

在我迄今为止所做的每一个基于SQL的数据库应用程序中,迟早会出现以下三方面的要求:

  • 有一些实体,以分层方式链接(即元组形成树结构)。
  • 用户必须能够使用元组的值定义任意数量的自定义属性,并且这些值将继承/覆盖树结构的叶子。 (“哑”属性通常就足够了。也就是说,没有唯一性约束,没有外键,每个属性只有一个值,......)
  • 用户必须能够对此数据运行任意查询(即自定义布尔表达式,基于与AND / OR链接的用户定义属性值的过滤器)。

存储数据,与上面的前两个项目符号大致匹配,非常简单:

  • 通过为相应的表提供 parent 列来构建层次结构。对于根节点,此列将为null,对于所有其他节点,此列将指向父节点的ID。
  • 根据entity-attribute-value pattern
  • 存储用户定义的属性

虽然有许多资源建议使用不同的方法,尤其是在后一点(例如answers hereherehere),但我通常不会处于某个位置远离传统的静态关系数据库模式。因此,让我们简单地将上述假设为给定的。而且,我几乎不可能依赖于特定DBMS的细节;更常见的情况是系统应该与MS SQL Server,Oracle以及可能的其他系统一起作为后端,而不需要两个明显不同的产品版本。

然而,解决第三个项目总是有问题的(即使不考虑属性值的分层继承)。连接数取决于布尔表达式中考虑的不同属性数。或者,通过确定在自定义布尔表达式的任何情况下考虑的不同属性的最大数量,可以稍微减少连接数,这可以节省连接,但是使得生成的查询和用于生成它们的代码更不易理解和可维护。例如,

a = 5 or (b = 8 and c = 9)

可以使用2个连接到属性值表。

我一直能够“以某种方式”这样做,但由于这似乎是一种相当普遍的情况,我正在寻找在这种情况下生成SQL查询的“规范”方法。这里有“标准模式”吗?

1 个答案:

答案 0 :(得分:1)

小心不要陷入内心平台效应。这是一个复杂的问题,SQL本身旨在处理复杂性。生成DDL以根据需要添加和删除列,并为查询生成简单的select语句。将每个元组类型(不同的属性集)存储为表格。

关于继承,我建议在应用程序或DAL中处理它,并且只存储非继承的值。在检索时,读取所有父行以计算功能值。如果确实需要从SQL访问“功能”值,请使用索引视图或触发器将它们与存储分开。

层次结构可以按照您的描述进行表示,但是简单的“父”列可能会使查询超出单个级别变得困难。查看SQL Server上的hierarchyid或oracle上的CONNECT BY

避免使用EAV商店可以:

  • 在需要时使用索引和统计信息
  • 保持有效存储空间(int存储为intmoney存储为money
  • 保持可理解的查询(SELECT * FROM vwProducts WHERE Color = 'RED' ORDER BY Price ASC

如果你想要一个EAV系统,因为你有太多的属性(每种类型大于1024)或者它们没有多少静态定义(每小时多次更改),我首先会避免使用关系数据库。请改用EAV(NoSQL)数据库服务器。

tl; dr:如果您有架构,请使用DDL告知服务器。如果不这样做,请使用更合适的服务器。