Joe*_*ool 11 database-design normalization entity-attribute-value
假设您正在收集有关即将发布的超级英雄电影的内幕信息,您的主电影表看起来像这样:
表格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
Run Code Online (Sandbox Code Playgroud)
这通常可以很好地工作,并允许非常简单的查询以及行之间的比较.
但是,您希望跟踪每个数据事实的来源,以及发现该事实的记者的姓名.这似乎暗示了某种类似这样的EAV表:
表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
...
Run Code Online (Sandbox Code Playgroud)
虽然它可以轻松捕获我们想要的元数据,但却更难以进行查询.简单地获取单个电影的所有基本数据需要更多.更具体地说,你必须在这里处理四行以获得绿灯侠上的四个重要信息,而在表1中它是一个单独的,封装良好的行.
所以我的问题是,鉴于我刚才描述的复杂情况,并且因为我知道EAV表一般要避免,EAV仍然是最好的解决方案吗?它似乎是表示此数据的唯一合理方式.我看到的唯一另一种选择是将表1与另一个仅包含元数据的表一起使用:
表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
...
Run Code Online (Sandbox Code Playgroud)
但这是非常危险的,因为如果有人将表1中的列名称更改为"小恶棍",那么表3中的行仍然会简单地说"恶棍",因此相关数据将很遗憾地解耦.如果"属性"列链接到另一个用作表1列的枚举的表,则可以帮助这一点.当然,DBA将负责维护此枚举表以匹配表1的实际列.实际上可以通过手动创建枚举表来进一步改进这一点,在SQL Server中使用系统视图,其中包含表1中列的名称.虽然我不确定您是否可以拥有涉及的关系系统视图.
你有什么建议?EAV是唯一的出路吗?
如果它只是一个元数据列(只有"源"而没有"记者"),那么它仍然需要走EAV路线吗?您可以拥有"Director","Director_Source","Leading Male","Leading Male_Source"等列,但这很快就会变得难看.我有没有想到更好的解决方案?
如果我没有澄清任何一点请评论,我会在必要时添加更多.哦是的,我用的电影数据是捏造的:)
编辑:简要地重述我的主要问题,我希望得到表1的简单性和真正的RDBMS设计,它真正描述了一个电影条目,同时仍然以安全和可访问的方式将元数据存储在属性上.这可能吗?或者EAV是唯一的方式?
编辑2:在做了更多的网络研究之后,我还没有找到关于EAV的讨论,这些讨论的核心是在列上存储元数据的愿望.实现EAV的主要原因几乎总是动态且不可预测的列,在我的示例中并非如此.在我的例子中,总有相同的四列:导演,男主角,女主角,反派.但是,我想存储关于每一行的每列的某些事实(来源和记者).EAV会促进这一点,但我想避免诉诸于此.
更新
使用表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
Run Code Online (Sandbox Code Playgroud)
您可以在设计中更改您认为是事实值的内容 ......您的数据模型中的事实似乎可以表示为以下N元组:
Movie | FactType | FactValue | FactSource | FactJournalist
Run Code Online (Sandbox Code Playgroud)
下表结构应该支持您想要的数据模型,并且可以相对容易地编制索引和连接.您还可以创建一个视图,仅显示事实值和事实类型,以便您可以创建以下透视图:
MovieID | Movie Name | Director | LeadingMale | LeadingFemale | PrimaryVillain | etc
Run Code Online (Sandbox Code Playgroud)
有趣的是,您可以认为这是将EAV模型完全应用于数据的逻辑扩展,并将单个电影(具有导演,导演,恶棍等的直观归属)分解为一个旋转结构,其中属性集中于源而是信息.
建议的数据模型的好处是:
数据模型的一些缺点是:
我将电影数据升级到一个级别以规范化结构,你可以将电影名称下移到MovieFact结构中以保持一致性(因为对于某些电影我可以想象,即使这样,你可能想要跟踪源信息的名称) .
Table Movie
========================
MovieID NUMBER, PrimaryKey
MovieName VARCHAR
Table MovieFact
========================
MovieID NUMBER, PrimaryKeyCol1
FactType VARCHAR, PrimaryKeyCol2
FactValue VARCHAR
FactSource VARCHAR
FactJournalist VARCHAR
Run Code Online (Sandbox Code Playgroud)
您的虚构电影数据将如下所示:
Movie Table
====================================================================================
MovieID MovieName
====================================================================================
1 Green Lantern
2 The Tick
MovieFact Table
====================================================================================
MovieID FactType FactValue FactSource FactJournalist
====================================================================================
1 Director Kubrick CHUD Sarah
1 Leading Male Robert Redford CHUD James
1 Leading Female Miley Cyrus Dark Horizons James
1 Villain Hugh Grant CHUD Sarah
2 Director Mel Gibson Yahoo Cameron
2 Leading Male John Lambert Yahoo Erica
...
Run Code Online (Sandbox Code Playgroud)