我们必须重新设计从MySQL到PostgreSQL的传统POI数据库。目前,所有实体都有80-120个属性,代表各个属性。
我们被要求考虑新数据库的灵活性和良好的设计方法。但是新设计应该允许:
n 没有。任何实体的属性/属性,即任何实体的属性都没有固定,可能会定期更改。
允许内容管理员使用管理界面向现有实体动态添加新属性,而不是始终在db架构中进行更改。
关于EAV的性能问题有很多讨论,但如果我们不采用混合EAV,我们最终会:
无论如何,这是我们对新设计的考虑(包括基本的ERD):
为每个实体提供单独的表格,其中包含一些独有的基本信息,例如: id,姓名,地址,联系方式,创建等等。
有2个表属性类型和属性来存储属性信息。
使用多对多关系将每个实体链接到属性。
将地址存储在不同的表中,并使用外键链接到实体。
我们认为这可以让我们在添加,删除或更新属性时更灵活。
然而,这种设计在获取数据时会导致连接数量增加,例如,为了显示给定体育场的所有“属性”,我们可能会有一个带有20多个连接的查询来获取单行中的所有相关属性。
您对此设计有何看法,以及您对改进设计的建议。
感谢您的阅读。
答案 0 :(得分:29)
我正在维护一个拥有10年历史的系统,该系统具有10M +实体,500M +值和数百个属性的中央EAV模型。我的经验中的一些设计考虑因素:
如果您有任何适用于特定属性的业务逻辑,则值得将该属性作为显式列。 EAV属性应该是通用的东西,应用程序不应该将属性A与属性B区分开。如果在代码中找到对EAV属性的文字引用,则可能是它应该是显式列。
拥有大量空列并不是一个很大的技术问题。它确实需要良好的编码和文档实践来划分最终出现在一个表中的不同问题:
Postgresql并不喜欢瘦表。除了遍历所有行以将数据拉到一起的额外工作之外,每个属性值还导致32字节的数据存储开销。如果您主要以批处理方式读取和写入属性,请考虑以某种方式将数据序列化到行中。 attr_ids int[], attr_values text[]
是一个选项,hstore是另一个选项,或者是客户端,如json或protobuf,如果你不需要触及数据库端的任何特定内容。
不要忘记把所有东西都放在一个单一的实体表中。如果他们不以合理的方式共享任何属性,请使用您使用的特定EAV模式的多个瞬时。但是请尝试使用相同的模式并在不同的实例之间共享任何访问者代码。您始终可以参数化实体名称上的代码。
始终牢记代码是数据,数据是代码。您需要在将决策推送到元模型并将其表示为代码之间找到正确的平衡。如果你让元模型做得太多,修改它将需要同样的能力来理解系统,版本控制工具,QA程序,作为你的代码暂存,但它没有任何工具。从本质上讲,您将使用非常笨拙的非标准语言进行编程。另一方面,如果您在代码中留下太多内容,那么每次微不足道的更改都需要新版本的软件。人们倾向于错误地使元模型过于复杂。为元模型构建开发人员工具是艰苦而乏味的工作,并且收益有限。另一方面,通过自动化从提交到部署发生的所有事情来使发布过程更便宜具有许多附带的好处。
答案 1 :(得分:6)
EAV对某些场景非常有用。但它有点像“黑暗的一面”。功能强大,灵活且引人入胜。但这是一个简单的出路。一种简单的方法,可以进行适当的分析和设计。
我认为“实体”有点过于笼统。您似乎对应该连接到该实体的内容有所了解,例如地址和联系人。如果您决定在模型中使用“书籍”,该怎么办?他们也会有地址和联系吗?我认为你应该尝试找到正确的概括,并将模型的EAV部分保持在minium。每当您发现自己想要显示属性的某个子集,或者测试值的存在,或者根据值确定行为时,您应该将其建模为列。
您将无法获得比现在更好的设计此系统的机会。自上一版本以来,这些要求是已知的,还有哪些有效,哪些无效。 (只是不要成为Second System Effect)的受害者
答案 2 :(得分:3)
可以在magento中找到EAV的一个很好的实现,magento是电子商务的cms。那些日子里有很多关于EAV的糟糕谈话,但我挑战任何人提出另一个解决方案而不是EAV来处理无限的产品属性。</ p>
当然,您可以列举世界上每件产品所需的所有列,但这会花费您很多时间,并且您将不可避免地忘记产品属性。</ p>
所以底线是:将EAV用于无限的东西,但不要依赖所有数据库表的EAV。因此,混合EAV和关系数据库,如果做得好,是一个功能强大的工具,仅使用固定列无法完成。
答案 3 :(得分:2)
基本上EAV试图在数据库中实现数据库,这会导致疯狂。提取数据的查询变得过于复杂,而且您的数据没有稳定的特定模型,无法保持某种顺序。
我为有限的应用程序编写了EAV系统,但作为通用解决方案,这通常是一个坏主意。