EAV的替代数据库设计

时间:2012-05-12 07:08:45

标签: sql entity-attribute-value

我需要在关系数据库(MySQL)中建模人员数据库。

每个人都有财产。有一些属性只有1:1的关系(例如男性/女性)和其他有1:n关系的属性,如体育或语言(例如,一个人可能会打篮球和踢足球,会说英语和德语)。另外,这些1:n关系具有技能水平(例如专业,初学者)。

目前我在问自己是否有比EAV模型更好的方法来模拟人 - 属性关系。我担心的主要是过滤那些有特殊属性的人更容易(例如所有演员都是男性和(专业打篮球或初学者)并且专业地说英语。应该可以轻松添加新属性(这必须如果这需要由开发人员完成并且需要更改表,那就没关系了。但它不应该很难(例如修改sql语句,添加连接,添加数据库表/查找表)

我会选择基于经典列的设计,在每个属性的单独列中的个人表中具有1:1属性。我不确定哪种是在这种设计中建模1:n关系的最佳方法。我想避免为每个1:n属性进行查找和单独的表。

最好的方法似乎仍然是以下EAV方法:

具有列id,例如

列的Persons表
1 | Christian 

属性表,其列为person_id,property,value,level,例如:

1 | gender   | male       |
1 | sports   | basketball | professional
1 | sports   | football   | beginner
1 | language | english    | professional
1 | language | german     | basic

2 个答案:

答案 0 :(得分:5)

如果您事先不了解数据架构,并且您不希望开发人员为每个新数据集修改系统,则最适合使用EAV。

从你所说的情况来看,情况并非如此。

EAV有许多缺点 - 例如,您不能依赖内置的关系模型来验证您的架构。因此,如果您的用户“Christian”没有指定其性别的值,则您的应用程序只需处理它 - 而在传统架构中,您有性别列,您声明“非null”,并链接到“性别“查找表。对于大多数应用程序来说,这是一个大问题 - 在应用程序级别强制执行数据的有效性并非易事。

EAV的第二大缺点是易于使用SQL的查询变得非常复杂,性能降低得相当快,因为​​where子句中的每个项(例如“where gender ='m'”)都成为子查询。

因此,我肯定会将您知道的架构数据建模为“传统”数据库。如果你想避免查找表,你可以 - 而不是拥有“性别”表的外键,你可以只依靠你的应用程序知道有效的选项是“m”和“f”(不要忘记处理这里可能发生的怪异 - “M”是有效的,而不是“m”吗?)。

为了模拟1:n关系,您可以创建一个单独的表,例如“person_sports”,与“person”表具有外键关系。你可以,也许应该也有一个“体育”的查找表,在这种情况下,你有一个多对多的关系。

答案 1 :(得分:0)

您的问题的答案实际上取决于数据库随着时间的推移会发生什么。以下是一些问题:

  • 添加新属性的频率是多少?
  • 新人加入的频率是多少?
  • 是批量添加新人还是一次添加一人?
  • 对于一个人而言,检索往往更多属于所有属性,还是对很多人来说只是一些属性?

如果您有一个开发期,其中添加了功能,然后在开发期间数据结构将稳定,请使用传统的E-R方法。在开发过程中,添加新列并不是特别繁重。

此外,如果您计划处理数百或数百个属性的数百万人,那么请考虑性能问题。这可能会阻止你进入EAV。

当您批量添加人员并一次只检索几个属性时,有一种替代数据库方法非常有效。曾几何时,这被称为垂直分区,但现在看起来似乎是列分区的名称。在此,您可以将不同的属性存储在不同的表中。 1-1属性将具有相同的主键,这应该使得连接在内存中非常快速 - 几乎是不显着的性能损失。对于1-n属性,您需要一个复合主键,其中person为第一个元素,默认情况下数据页面未满(这允许您在同一数据页面上进行更新)。

添加新属性只需要添加一个新表来存储它,为现有人填充它,以及更改数据库上的任何视图以使用它。

某些商业数据库专门用于此类结构(例如Vertica),但它们比mysql贵得多。