假设您正在收集有关即将上映的超级英雄电影的内部信息,并且您的主电影表如下所示:
Table 1
Title Director Leading Male Leading Female Villain
--------------------------------------------------------------------------
Green Lantern Kubrick Robert Redford Miley Cyrus Hugh Grant
The Tick Mel Gibson Kevin Sorbo Linda Hunt Anthony Hopkins
一般来说,这应该工作得很好,并且允许非常简单的查询以及行之间的比较。
但是,您希望跟踪每个数据事实的来源,以及发现该事实的记者的姓名。这似乎表明某种EAV像这样的表:
Table 2
Movie Attribute Value Source Journalist
----------------------------------------------------------------------------------
Green Lantern Director Kubrick CHUD Sarah
Green Lantern Leading Male Robert Redford CHUD James
Green Lantern Leading Female Miley Cyrus Dark Horizons James
Green Lantern Villain Hugh Grant CHUD Sarah
The Tick Director Mel Gibson Yahoo Cameron
...
虽然它可以轻松捕获我们想要的元数据,但会使查询变得更加困难。简单地获取一部电影的所有基本数据需要更多的时间。更具体地说,您必须在这里处理四行才能获取有关 Green Lantern 的四个重要信息,而在表 1 中它是一个单独的、封装良好的行。
所以我的问题是,鉴于我刚才描述的复杂性,并且因为我知道通常要避免 EAV 表,EAV 仍然是最佳解决方案吗?这似乎是表示这些数据的唯一合理的方式。我看到的唯一的其他替代方案是将表 1 与另一个仅包含如下元数据的表结合使用:
Table 3
Movie Attribute Source Journalist
----------------------------------------------------------------------------------
Green Lantern Director CHUD Sarah
Green Lantern Leading Male CHUD James
Green Lantern Leading Female Dark Horizons James
Green Lantern Villain CHUD Sarah
The Tick Director Yahoo Cameron
...
但这是非常危险的,因为如果有人更改表 1 中的列名,例如将“Villain”更改为“Primary Villain”,表 3 中的行仍然会简单地显示“Villain”,因此相关数据将不幸被解耦。如果“属性”列链接到另一个表,该表充当表 1 的列的枚举,这可能会有所帮助。当然,DBA 将负责维护此枚举表以匹配表 1 的实际列。实际上,可以通过使用 SQL Server 中包含表 1 中列名的系统视图,而不是手动创建枚举表来进一步改进这一点。虽然我不确定您是否可以拥有涉及以下的关系:系统视图。
你有什么建议? EAV 是唯一的出路吗?
如果只有一个元数据列(只是“来源”,没有“记者”)怎么办?是否还有必要走 EAV 路线?您可以有“Director”、“Director_Source”、“Leading Male”、“Leading Male_Source”等列,但这很快就会变得丑陋。还有我没有想到的更好的解决方案吗?
如果我没有澄清任何一点,请发表评论,我会根据需要添加更多内容。哦,是的,我使用的电影数据是捏造的:)
编辑:为了简明地重申我的主要问题,我希望表 1 具有简单性和真正的 RDBMS 设计,它真正很好地描述了电影条目,同时仍然以安全且可访问的方式存储属性上的元数据。这可能吗?或者EAV是唯一的方法吗?
编辑 2:在做了更多的网络研究之后,我还没有找到关于 EAV 的讨论,该讨论集中在将元数据存储在列上的愿望上。实现 EAV 的主要原因几乎总是动态且不可预测的列,但我的示例中并非如此。在我的例子中,总是有相同的四栏:导演、男主角、女主角、反派。但是,我想存储有关每行每列的某些事实(来源和记者)。 EAV 可以促进这一点,但我想避免这样做。
Update
使用表 2 的设计,除了将列“Movie”重命名为“Name”并将整个表命名为“Movie”之外,下面是 SQL Server 2008 中返回表 1 的透视操作:
SELECT Name, [Director], [Leading Male], [Leading Female], [Villain]
FROM (Select Name, Attribute, Value FROM Movie) as src
PIVOT
(
Max(Value)
FOR Attribute IN ([Director], [Leading Male], [Leading Female], [Villain])
) AS PivotTable