我们的数据库是基于EAV(实体 - 属性 - 值)模型设计的。那些使用EAV模型的人知道为了灵活性而附带的所有垃圾。
我向我的客户询问了使用EAV模型的原因(灵活性),他们的反应是:他们的实体随着时间而变化。因此,今天他们可能有一个具有一些属性的表,但在一个月的时间内,可能会添加一些新属性,或者可能会重命名现有属性。他们需要生成报告以回到任何阶段,并根据该阶段的实体形状查询数据。
我理解这对于传统的关系模型是不可行的,但我个人认为EAV是反模式的。是否有其他替代模型使我们能够捕获实体和实例更改的时间维度?
干杯, MOSH
答案 0 :(得分:50)
忠实或严重的EAV之间存在差异; 5NF由熟练的人或无能为力的人完成。
第六范式是不可简化的范式(不可能进一步标准化)。它消除了许多常见的问题,例如空问题,并提供了识别缺失值的最终方法。它是学术上和技术上强大的NF。没有产品可以支持它,并且它不常用。要正确且一致地实施,需要实现元数据目录。当然,导航它所需的SQL变得更加麻烦(SQL已经是繁琐的重新连接),但通过从元数据自动生成SQL可以轻松克服这一点。
EAV是6NF的部分集合或子集。问题是,通常是为了一个目的(允许添加列而不必进行DDL更改),以及不了解6NF且不实现元数据的人。关键是,6NF和EAV作为原则和概念提供了实质性的好处,并且性能提高了;但通常没有正确实施,并没有实现好处。相当多的EAV实施都是灾难,不是因为EAV不好,而是因为实施很差。
EG。有些人认为从6NF / EAV数据库构建3NF行所需的SQL很复杂:不,它很麻烦但不复杂。更重要的是,可以提供普通的SQL VIEW,以便所有用户和报告工具只能看到直接的3NF VIEW,并且6NF / EAV问题对他们来说是透明的。最后,所需的SQL可以自动化,因此许多人忍受的劳动力成本是非常不必要的。
所以答案真的是,作为EAV之父的第六范式,以及更纯粹的形式,是它的替代品。警告是,确保它正确完成。我有一个大的6NF数据库,它没有人们发布的任何问题,它表现得很漂亮,客户非常高兴(没有进一步的工作是完全功能满意的标志)。
我已经发布了另一个适用于您的问题的问题的详细答案,您可能会感兴趣。
答案 1 :(得分:9)
无论您使用哪种关系模型,跟踪字段名称更改都需要大量元数据,您必须在事务日志或审计表中跟踪这些元数据。不幸的是,在特定日期查询州内的任何一个都非常复杂。如果您的客户端仅在特定时间日期需要状态,但意味着整个状态,而不仅仅是名称更改,您可以复制数据库并将事务日志回滚到所需的特定时间并在新实例上运行查询。如果在指定日期之后添加的实体需要显示在具有旧字段名称的查询中,则您面临着非常大的工程问题。在这种情况下,根据您在问题中提供的信息,我建议您与客户协商替代方案,或者获取有关使用报告的更多信息以寻找替代解决方案。
您可以转移到基于文档的数据存储区,但在第二种情况下仍然无法解决问题。对不起,这不是一个真正的答案,但是在遇到类似情况的情况下,客户可能需要一个更加切合实际的报告解决方案,或者其他许多投资者愿意将资金用于工程。
当我们遇到此问题时,我们保持db模式不变并基于时间戳实现实体映射工厂。最后,客户不断改变要求(每周一次),以确定如何计算总计字段,并且从未完全满意。
答案 2 :(得分:0)
添加@NickLarsen和@PerformanceDBA的答案
如果您需要跟踪字段名称等内容的历史更改,您可能需要查看Slowly Changing Dimensions之类的内容。在我看来,你正在使用EAV来模拟动态维模型(可能是查找列表)。
实现这一目标的最简单(也可能是效率最低)的方法是在EAV表中包含“as as”日期字段,并且每当发生更改时,插入新记录(而不是更新现有记录)当前的日期。这意味着您需要更改您的查询以始终包含或查找“截至日期”,或者如果没有提供,则嘲笑“现在”。然后,连接到EAV对象的基本实体必须从EAV表中查询“top 1”,其中“截至日期”小于或等于该行的“最后更新”日期,按“截至”排序降。最糟糕的情况是,如果您需要跟踪给定行的最近更改,其中名称(存储在“属性”表中)和值已更改,您可以使用“上次修改”将此逻辑链接到值表该行的行,以找到该特定日期的适当值。
如果有很多变化,这显然有可能产生大量数据。这就是为什么这种方法被称为“缓慢”变化的原因。它适用于可能发生变化的尺寸值,但不常见。为了帮助提高查询性能,“截至”和“最后修改”字段的索引应该有所帮助。
答案 3 :(得分:-1)
为每个实体描述版本创建新的表描述 和一个额外的表,告诉你哪个表是哪个版本。 查询系统也应该更新。
我认为创建生成,表格和查询的脚本是最好的选择。