database-design – 这个数据库结构有名称吗?

我们处理来自客户端的例程数据馈送,该客户端刚刚从一个看似熟悉的表单(每个实体一行,每个属性一列)重构数据库到我认为不熟悉的表单(每个属性每个实体一行):

之前:每个属性一列

ID   Ht_cm   wt_kg   Age_yr  ... 
1      190      82     43    ...
2      170      60     22    ...
3      205      90     51    ...

之后:所有属性都有一列

ID    Metric   Value
 1     Ht_cm     190
 1     Wt_kg     82
 1     Age_yr    43
 1      ...
 2     Ht_cm     170
 2     Wt_kg     60
 2     Age_yr    22
 2     ...
 3     Ht_cm     205
 3     Wt_kg     90
 3     Age_yr    51
 3     ...

这个数据库结构有名称吗?有什么相对优势?旧方法似乎更容易将有效性约束置于特定属性(非空,非负等)并且更容易计算平均值.但是我可以看到在不重构数据库的情况下添加属性会更容易.这是构建数据的标准/首选方式吗?

解决方法

它被称为实体 – 属性 – 值(有时也称为“名称 – 值对”),当人们在关系数据库中使用EAV模式时,它是“方孔中的圆钉”的经典案例.

以下是您不应使用EAV的原因列表:

>您不能使用数据类型.如果值是日期,数字或金钱(十进制),则无关紧要.它总是会被强制转换为varchar.这可能是从轻微的表现问题到巨大的痛苦(在月度汇总报告中追逐1美分的差异?).
>您不能(轻松)强制执行约束.它需要一些荒谬的代码才能强制执行“每个人都需要高度在0到3米之间”或“年龄必须不为空且> = 0”,而不是1-2行,每个约束都会处于适当建模的系统中.
>与上述相关,您不能轻易保证您获得每个客户所需的信息(一个人可能缺少年龄,然后下一个可能会丢失他们的身高等).你可以做到这一点,但它比SELECT高度,重量,年龄FROM客户高难度或权重为空是一个很难的地方.
>再次相关,重复数据更难以检测(如果它们为一个客户端提供两个年龄会发生什么?如果你有一个属性翻倍,去除数据,如下所示,将给你两行结果.如果一个客户端有两个单独的两个属性条目,您将从下面的查询中获得四行).
>您甚至无法保证属性名称是一致的. “Age_yr”可能变为“AGE_IN_YEARS”或“age”. (不可否认,当您收到摘录时,与人们插入数据时相比,这不是问题,但仍然如此.)
>任何形式的重要查询都是一场彻底的灾难.为了使三属性EAV系统关系化以便您能够以合理的方式查询它需要EAV表的三个连接.

相比:

SELECT cID.ID AS [ID],cH.Value AS [Height],cW.Value AS [Weight],cA.Value AS [Age]
FROM (SELECT disTINCT ID FROM Client) cID 
      LEFT OUTER JOIN 
    Client cW ON cID.ID = cW.ID AND cW.Metric = "Wt_kg" 
      LEFT OUTER JOIN 
    Client cH ON cID.ID = cH.ID AND cW.Metric = "Ht_cm" 
      LEFT OUTER JOIN 
    Client cA ON cID.ID = cA.ID AND cW.Metric = "Age_yr"

至:

SELECT c.ID,c.Ht_cm,c.Wt_kg,c.Age_yr
FROM Client c

这是一个(非常简短的)列表,您应该何时使用EAV:

>如果没有办法解决问题,您必须在数据库支持无模式数据.
>当你只需要存储“东西”而不希望以更结构化的形式需要它时.但要注意,这个怪物叫做“改变要求”.

我知道我只是花了整整一篇文章详细说明为什么在大多数情况下EAV是一个可怕的想法 – 但有一些情况需要/不可避免.然而,在大多数情况下(包括上面的例子),它将比它的价值更麻烦.如果您需要广泛支持EAV类型的数据输入,您应该考虑将它们存储在键值系统中,例如: Hadoop / HBase,CouchDB,MongoDB,Cassandra,BerkeleyDB.

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 'EastRiver' 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...