0

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

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

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

我会采用经典的基于列的设计,将 person 表中的 1:1 属性放在每个属性的单独列中。我不确定在这样的设计中,哪一种是建模 1:n 关系的最佳方式。我想避免为每个 1:n 属性查找和单独的表。

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

具有列 id、name 的 Persons 表,例如

1 | 基督教 

具有列 person_id、property、value、level 的 Properties 表,例如:

1 | 性别 | 男|
1 | 运动 | 篮球 | 专业的
1 | 运动 | 足球 | 初学者
1 | 语言 | 英语 | 专业的
1 | 语言 | 德语 | 基本的
4

2 回答 2

5

EAV 最适合当您事先不知道数据的架构,并且您不希望开发人员为每组新数据修改您的系统时。

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

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

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

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

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

于 2012-05-12T10:35:32.600 回答
0

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

  • 多久添加一次新属性?
  • 多久会添加一次新人?
  • 是批量添加还是一次添加一个?
  • 对于一个人来说,检索往往是更多的属性,还是对于很多人来说只是几个属性?

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

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

当您批量添加人员并一次仅检索几个属性时,还有一种替代数据库方法非常有效。曾几何时,这被称为垂直分区,但现在似乎被称为列分区。在这种情况下,您可以将不同的属性存储在不同的表中。1-1 属性将具有相同的主键,这应该会使连接在内存中快速运行——几乎不会对性能造成明显影响。对于 1-n 属性,您需要一个复合主键,以人作为第一个元素,以及默认情况下不完整的数据页(这允许您在同一数据页上进行更新)。

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

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

于 2012-05-12T16:04:24.987 回答