实体属性值(EAV)的替代scheme?

我们的数据库是基于EAV(Entity-Attribute-Value)模型devise的。 那些曾经使用过EAV模型的人,为了灵活性而知道所有的垃圾。

我问客户有关使用EAV模型(灵活性)的原因,他们的回答是:他们的实体随着时间而改变。 所以,今天他们可能有一个有几个属性的表,但在一个月的时间里,可能会添加一些新的属性,或者现有的属性可能会被重命名。 他们需要生成报告以及时返回到任何阶段,并根据当前实体的形状查询数据。

我知道这对传统的关系模型来说是不可行的,但我个人认为EAV是反模式的。 是否有其他的替代模型,使我们能够捕捉实体和实例变化的时间维度?

干杯,Mosh

EAV差别很大, 5NF由技术熟练的人员或无知者完成。

第六范式是不可简化的范式(不能进一步标准化)。 它消除了很多常见的问题,如The Null Problem,并提供了识别缺失值的最终方法。 这是在学术和技术上强大的NF。 没有产品可以支持,而且不常用。 为了得到正确和一致的实施,它需要一个元数据的目录来实施。 当然,导航它所需的SQL变得更加繁琐(SQL重新连接繁琐),但是通过从元数据中自动生成SQL可以轻松解决这个问题。

EAV是6NF的部分集合或子集。 问题是,通常是为了某个目的(允许添加列而不必进行DDL更改),以及不知道6NF的人以及谁不实现元数据。 重点是,6NF和EAV作为原则和概念提供了实质性的好处,并且性能提高; 但一般情况下执行不当,效益不明显。 不lessEAV实施都是灾难性的,并不是因为EAV不好,而是因为实施效果差。

例如。 有人认为,从6NF / EAV数据库构build3NF行所需的SQL是复杂的:不,这很麻烦,但并不复杂。 更重要的是,可以提供一个普通的SQL VIEW,以便所有用户和报表工具只能看到直接的3NF VIEW,而6NF / EAV问题对他们来说是透明的。 最后,所需的SQL可以自动化,所以许多人忍受的人工成本是不必要的。

所以答案的确是,第六范式,是EAV的父亲,更纯粹的forms,是它的替代品。 注意事项是,确保正确完成。 我有一个大的6NF分贝,它不会有人发布的问题,performance非常好,客户很高兴(没有进一步的工作是一个完整的function满意的标志)。

我已经发布了一个非常详细的答案,也适用于您的问题,您可能会感兴趣的另一个问题。

其他的EAV问题

无论您使用哪种关系模型,跟踪字段名称更改都需要大量的元数据,您必须在事务日志或审计表中logging这些元数据。 不幸的是,在某个特定date查询其中的任何一个状态是非常复杂的。 如果您的客户端只需要特定时间date的状态,则意味着整个状态,而不仅仅是名称更改,您可以复制数据库并将事务日志回滚到所需的特定时间,并对新实例运行查询。 如果在指定date之后添加的实体需要使用旧字段名称显示在查询中,则在您面前有一个非常大的工程问题。 在这种情况下,根据您在问题中提供的信息,我会build议您与客户谈判替代scheme,或者获取有关使用报告的更多信息以寻找其他解决scheme。

你可以移动到一个基于文档的数据存储,但这仍然不能解决第二种情况下的问题。 对不起,这不是一个真正的答案,但是在类似的情况下,客户可能需要一个更现实的报告解决scheme或其他投资者愿意为工程提供资金。

当我们遇到这个问题时,我们保持数据库模式不变,并根据时间戳实现一个实体映射工厂。 最后,客户不断地改变需求(每周到每月),计算总计字段的方式,从未完全满意。

从@NickLarsen和@PerformanceDBA添加到答案

如果您需要跟踪字段名称等历史更改,则可能需要查看“ 渐变维度”(Slowly Changing Dimensions)等内容 。 在我看来,您正在使用EAV来build模dynamic维度模型(可能查找列表)。

最简单的(也可能是效率最低的)实现方法是在EAV表中包含一个“asof”date字段,每当发生更改时,用当前date插入新logging(而不是更新现有logging)。 这意味着你需要改变你的查询,以便始终包含或查找“截至”date,或者如果没有提供,可以将它们设置为“现在”。 join到EAV对象的基本实体然后必须从EAV表中查询“top 1”,其中“asof”date小于或等于该行的“最后更新”date,按照“asof”降。 最糟糕的情况是,如果您需要跟踪给定行的最近更改,其中名称(存储在“属性”表中)和值已更改,则可以使用“上次修改”将此逻辑链接到值表find该date的适当值。

如果有很多变化,这显然有可能产生大量的数据。 这就是为什么这种方法被称为“缓慢”的变化。 它的目的是可能会改变的尺寸值,但不是经常。 为了帮助查询性能,“as of”和“last modified”字段上的索引应该有所帮助。

为每个实体描述版本和一个附加表格创build一个新的表格描述,告诉你哪个表格是哪个版本。 查询系统也应该更新。

我认为创build一个脚本生成,表和查询是你最好的select。