我们被要求考虑灵活性以及新数据库的良好设计方法。但新设计应允许:
>不,的任何实体的属性/属性,即任何实体的属性不是固定的,并且可以定期更改。
>允许内容管理员通过管理界面即时向现有实体添加新的属性,而不是一直在进行数据库模式的更改。
对EAV的性能问题进行了不少的讨论,但是如果我们不采用混合EAV,我们最终会发现:
>有很多空列(我们仍然去添加新列,即使99%的数据没有这些属性)
>花更多时间维护数据库。属性不断变化。
>没有办法允许内容管理员向现有实体添加新属性
无论如何,这里是我们正在考虑的新设计(包括基本的ERD):
>为每个实体提供单独的表,其中包含一些基本信息,例如id,name,address,contact,created等等
>有2个表属性类型和属性来存储属性信息。
>使用多对多关系将每个实体链接到一个属性。
>将地址存储在不同的表中,并使用外键链接到实体。
然而,这种设计将导致在提取数据时增加数量的连接,例如显示给定体育场的所有“属性”,我们可能会使用20个连接查询以获取单个行中的所有相关属性。
你对这个设计的看法是什么,你的建议是什么呢?
谢谢你的阅读。
解决方法
如果您有任何适用于特定属性的业务逻辑,那么将该属性视为显式列即可。 EAV属性应该是通用的东西,应用程序不应该将属性A与属性B区分开来。如果在代码中找到EAV属性的文字引用,那么它应该是一个显式的列。
拥有大量空列不是一个很大的技术问题。它确实需要良好的编码和文档实践来区分一个表中的不同问题:
>有约定和规则,让您知道应用程序的哪一部分读取和修改数据的哪一部分。
>使用视图可以使用调试工具来缓解数据库周围的斑点。
>创建和维护测试数据生成器,以便您可以轻松地为您当前不感兴趣的模型部分轻松创建符合模式的虚拟数据。
>使用严格的数据库版本控制。进行架构更改的唯一方法应该是通过跟踪和应用更改脚本的工具。 Postgresql具有事务性DDL,这是自动化模式更改的一个杀手功能。
Postgresql并不喜欢瘦的表。每个属性值都会导致32字节的数据存储开销,除了遍历所有行的额外工作以将数据拉到一起。如果您大多读取和写入属性作为批处理,请考虑以某种方式将数据序列化到行中。 attr_ids int [],attr_values text []是一个选项,hstore是另一个,或客户端,如json或protobuf,如果您不需要触摸数据库端的任何特定的东西。
不要把你的一切都放在一个单一的实体表中。如果他们不以合理的方式共享任何属性,请使用您使用的特定EAV模式的多个实例。但是尝试使用相同的模式,并在不同的instation之间共享任何访问器代码。您可以随时对实体名称的代码进行参数化。
请记住,代码是数据,数据是代码。您需要在将决策推入元模型并将其表示为代码之间找到正确的平衡。如果您使元模型做得太多,修改它将需要同样的能力来了解系统,版本控制工具,QA过程,分段作为代码,但它不会有任何工具。从本质上讲,您将以非常尴尬的非标准语言进行编程。另一方面,如果你在代码中留下太多的东西,那么每一个微不足道的变化都需要一个新版本的软件。人们倾向于错误地使元模型太复杂。构建元模型的开发工具是非常繁琐的工作,效益有限。另一方面,通过使提交部署中发生的所有事情自动化,使发布流程更便宜,有许多优点。