38

我们的数据库是基于EAV(Entity-Attribute-Value)模型设计的。那些与EAV模型合作过的人都知道为了灵活性所带来的所有弊端。实体属性值(EAV)的替代方法?

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

我明白这对传统的关系模型是不可行的,但我个人认为EAV是反模式。是否有其他可供选择的模型使我们能够捕捉实体和实例更改中的时间维度?

干杯, MOSH

+2

与其取代你所拥有的东西,因为它确实满足特定的需求,你应该考虑用随时间存储变化的东西来扩充你的基本EAV模型。 – RibaldEddie 2010-10-29 05:24:29

+0

我同意RibaldEddie,它不会很简单,但为您的Attribute定义添加日期/版本可能会比完全重构构建在当前架构上的所有代码更容易。 – JeremyWeir 2010-10-29 05:47:03

+4

有没有可能关闭这个?无论是评论和进展,还是投票和选择答案。谢谢。 – PerformanceDBA 2011-01-25 12:32:33

回答

-1

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

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

8

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

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

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

+1

优秀的回应。我会补充说一些客户将会完全不满意,因为他们不接受数据模型的最终灵活性和长期一致性之间的权衡。你只需要学习如何管理这些客户,并防止他们破坏你的生活或你的声誉。 – 2010-10-29 15:19:42

46

EAV完全忠诚或严重不同; 5NF由技术熟练的人员或无知者完成。

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

EAV是6NF的部分集合或子集。问题在于,通常是为了某种目的(允许添加列而无需进行DDL更改)以及不知道6NF的人以及不实现元数据的人员完成的。重点是,6NF和EAV作为原则和概念提供了实质性的好处,并且性能提高;但通常它没有得到正确执行,而且没有实现好处。不少EAV的实施都是灾难性的,不是因为EAV不好,而是因为实施效果差。

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

所以答案的确是,第六范式,是EAV的父亲,是一个更纯粹的形式,是它的替代品。注意事项是,确保它正确完成。我有一个大的6NF数据库,它没有任何人员发布的问题,它执行得很漂亮,客户很高兴(没有进一步的工作是完全功能满意的标志)。

我已经发布了一个非常详细的回答另一个问题,它适用于你的问题还有,你可能会感兴趣。

Other EAV Question

0

为了增加从@NickLarsen和@PerformanceDBA答案

如果您需要跟踪字段名称等历史更改,您可能需要查看诸如Slowly Changing Dimensions之类的内容。在我看来,您似乎正在使用EAV来建模动态维度模型(可能是查找列表)。

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

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