是EAV - Hybrid是一个糟糕的数据库设计选择

nka*_*nka 17 database postgresql database-design entity-attribute-value

我们必须重新设计从MySQL到PostgreSQL的传统POI数据库.目前,所有实体都有80-120个属性,代表各个属性.

我们被要求考虑新数据库的灵活性和良好的设计方法.但是新设计应该允许:

  • ñ没有.任何实体的属性/属性,即任何实体的属性都没有固定,可能会定期更改.

  • 允许内容管理员,以新的属性添加到现有实体上飞使用通过管理界面,而不是使在DB模式的改变所有的时间.

有关EAV性能问题的讨论很多,但如果我们不采用混合EAV,我们最终会:

  • 有很多空列(即使99%的数据没有这些属性,我们仍然会添加新列)
  • 花更多时间维护数据库esp.当属性不断变化时.
  • 无法允许内容管理员向现有实体添加新属性

无论如何,我们正在考虑新设计(包括基本ERD):

  • 为每个实体提供单独的表,其中包含一些独有的基本信息,例如id,name,address,contact,created等.

  • 有2个表属性类型和属性来存储属性信息.

  • 使用多对多关系将每个实体链接到属性.

  • 将地址存储在不同的表中,并使用外键链接到实体.

替代文字

我们认为这将使我们在添加,删除或更新属性时更加灵活.

然而,这种设计将在获取数据时导致连接数量增加,例如,为了显示给定体育场的所有"属性",我们可能具有20个以上连接的查询以获取单行中的所有相关属性.

您对此设计有何看法,以及您对改进设计的建议.

谢谢你的阅读.

Ant*_*sma 30

我正在维护一个拥有10年历史的系统,该系统具有10M +实体,50​​0M +值和数百个属性的中央EAV模型.根据我的经验进行一些设计考虑

如果您有任何适用于特定属性的业务逻辑,则值得将该属性作为显式列.EAV属性应该是通用的东西,应用程序不应该将属性A与属性B区分开.如果在代码中找到对EAV属性的文字引用,则可能是它应该是显式列.

拥有大量空柱不是一个很大的技术问题.它确实需要良好的编码和文档实践来划分最终在一个表中的不同关注点:

  • 有一些约定和规则可以让您知道应用程序的哪个部分读取并修改数据的哪个部分.
  • 使用视图可以使用调试工具轻松调整数据库.
  • 创建和维护测试数据生成器,以便您可以轻松地为当前不感兴趣的模型部分创建符合模式的模拟数据.
  • 使用严格的数据库版本控制.进行模式更改的唯一方法应该是通过跟踪和应用更改脚本的工具.Postgresql具有事务性DDL,这是自动化模式更改的一个杀手级功能.

Postgresql并不喜欢瘦表.除了遍历所有行以将数据拉到一起的额外工作之外,每个属性值还导致32字节的数据存储开销.如果您主要以批处理方式读取和写入属性,请考虑以某种方式将数据序列化到行中.attr_ids int[], attr_values text[]是一个选项,hstore是另一个选项,或客户端,如json或protobuf,如果您不需要触摸数据库端的任何特定内容.

不要忘记把所有东西都放在一个单一的实体表中.如果他们不以合理的方式共享任何属性,请使用您使用的特定EAV模式的多个瞬时.但是请尝试使用相同的模式并在不同的实例之间共享任何访问者代码.您始终可以参数化实体名称上的代码.

始终牢记代码是数据,数据是代码.您需要在将决策推送到元模型并将其表示为代码之间找到正确的平衡.如果你让元模型做得太多,修改它将需要同样的能力来理解系统,版本控制工具,QA程序,作为你的代码暂存,但它没有任何工具.从本质上讲,您将使用非常笨拙的非标准语言进行编程.另一方面,如果您在代码中留下太多内容,那么每次微不足道的更改都需要新版本的软件.人们倾向于错误地使元模型过于复杂.为元模型构建开发人员工具是艰苦而乏味的工作,并且收益有限.另一方面,通过自动化从提交到部署发生的所有事情来使发布过程更便宜具有许多附带的好处.


Ron*_*nis 6

EAV对某些场景非常有用.但它有点像"黑暗的一面".功能强大,灵活且引人入胜.但这是一个简单的出路.一种简单的方法,可以进行适当的分析和设计.

我认为"实体"有点过于笼统.您似乎对应该连接到该实体的内容有所了解,例如地址和联系人.如果您决定在模型中使用"书籍",该怎么办?他们也会有地址和联系吗?我认为你应该尝试找到正确的概括,并将模型的EAV部分保持在minium.每当您发现自己想要显示属性的某个子集,或者测试值的存在,或者根据值确定行为时,您应该将其建模为列.

你现在不会有比现在更好的机会来设计这个系统.自上一版本以来,这些要求是已知的,还有哪些有效,哪些无效.(只是不要成为第二个系统效应的受害者)


Sco*_*owe 2

基本上,EAV 试图在数据库中实现数据库,这会导致疯狂。提取数据的查询变得过于复杂,并且您的数据没有稳定的特定模型来保持某种顺序。

我已经为有限的应用程序编写了 EAV 系统,但作为通用解决方案,这通常是一个坏主意。

  • 但是,如果您将“属性”字段中的所有属性存储为 blob,那么如何使用属性过滤查询呢?这必须在应用程序中完成,如果我们谈论许多结果,这可能会导致高(不必要的)内存消耗。 (6认同)