实体-属性-值 (EAV) 的替代方案?

Posted

技术标签:

【中文标题】实体-属性-值 (EAV) 的替代方案?【英文标题】:Alternatives to Entity-Attribute-Value (EAV)? 【发布时间】:2011-05-02 05:45:19 【问题描述】:

我们的数据库是基于 EAV(实体-属性-值)模型设计的。那些使用过 EAV 模型的人都知道为了灵活性而附带的所有废话。

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

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

干杯, 莫什

【问题讨论】:

与其替换现有的东西,因为它确实满足特定需求,您应该考虑使用存储随时间变化的东西来扩充您的基本 EAV 模型。 我同意 RibaldEddie 的观点,这并不简单,但在属性定义中添加日期/版本可能比完全重构基于当前架构的所有代码更容易。 有没有机会解决这个问题?要么 cmets 和进度,要么投票和选择答案。谢谢。 【参考方案1】:

补充@NickLarsen 和@PerformanceDBA 的答案

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

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

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

【讨论】:

【参考方案2】:

EAV 做得好还是坏是有区别的; 5NF 由熟练的人或无能的人完成。

第六范式是不可约范式(不可能进一步归一化)。它消除了许多常见的问题,例如空问题,并提供了识别缺失值的终极方法。它是学术和技术上稳健的 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 db,它没有遇到人们发布的任何问题,它表现出色,客户非常满意(没有进一步的工作是功能完全满意的标志)。

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

Other EAV Question

【讨论】:

你能评论一下你的实现的具体线索吗?这似乎并不容易,而且往往是一场彻底的灾难......【参考方案3】:

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

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

当我们遇到这个问题时,我们保持 db 模式不变,并实现了一个基于时间戳的实体映射工厂。最后,客户不断改变要求(每周到每月)关于如何计算聚合字段并且从未完全满足。

【讨论】:

反应很好。我要补充一点,有些客户会完全不满意,因为当涉及到数据模型时,他们不接受最终灵活性和长期一致性之间的权衡。您只需要学习如何管理此类客户并防止他们破坏您的生活或声誉。【参考方案4】:

为每个实体描述版本创建一个新的表描述 还有一张额外的表格,告诉您哪个表格是哪个版本。 查询系统也应该更新。

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

【讨论】:

以上是关于实体-属性-值 (EAV) 的替代方案?的主要内容,如果未能解决你的问题,请参考以下文章

保管 EAV 的最佳实践

实体框架 - 分离和重新附加实体?

雄辩的 ORM 和 EAV

实体属性值数据库与严格的关系模型电子商务

magento产品eav笔记持续跟新...

mysql-阅读笔记1