代码之家  ›  专栏  ›  技术社区  ›  Mihir

EntityAttributeValue表(EAV表)是否需要单独的ID字段作为主键或复合主键(如entityId+attributeId)?

  •  0
  • Mihir  · 技术社区  · 9 年前

    这是我的EAV表结构(我知道EAV不好,但我需要存储的属性数量超过一万个,所以标准化表不起作用)

    Table name - propertyAssign
    
    entityId - int - indexed
    attributeId - smallint - composite index with valueId
    valueId - smallint - composite index with attributeId
    

    我只需要用两种方式查询这个表。

    1. 从propertyAssign中选择attributeId,valudId,其中entityId=x
    2. 从propertyAssign中选择entityId,其中attributeId=x,valueId=y

    所以我相应地添加了索引。

    问题=>我需要在这里添加主键吗?

    2 回复  |  直到 9 年前
        1
  •  1
  •   Rick James diyism    9 年前

    Renzo的回答包括选择#1,但不是

    select entityId from propertyAssign where attributeId=x and valueId=y
    

    这需要

    INDEX(attributeId, valueId, entityId)
    

    这将是

    • 高效,因为它完美地处理 WHERE 条款,以及
    • 更高效,因为 INDEX 包含所需的所有字段(“覆盖索引”)。

    是的,这实际上使表的大小加倍(数据+PK,然后是包含所有数据的索引)。但它是 比为Select#2进行表格扫描要好。

    闻起来像 attributeId valueId 是否链接到具有实际字符串和值的“标准化”表??在哪里 JOIN 需要完成代码吗?如果你是在一个单独的 SELECT ,那么这比 加入 因为它是两个(还是三个?)往返服务器。

    EAV是一种非常糟糕的设计模式;祝你好运

    编辑

    这两个 SELECTs 将受益于这两个指标:

     INDEX(entityId, attributeId, valueId) -- for Select #1
     INDEX(attributeId, valueId, entityId) -- for Select #2
    

    而且,既然那三个是独一无二的,一个或另一个 索引 也可以是 PRIMARY KEY 。现在,选择哪个。。。

    什么时候 INSERTing ,PK开始于 entityId 使得实体的所有三元组都“聚集”在一起。这将加快 INSERT 选择 #1.所以我投票支持它成为PK。让另一个成为PK不会加快 INSERTs 这是因为创建具有大量属性的实体将导致大量分散的写入。

    两个中的每一个 选择 由一个或另一个索引最佳地处理;所以 选择 尽可能快。我忽略了一个事实,即您规范了属性名称和值。这是我以后咬你的话,会让你提出更丑陋的问题。

    我认为这是一个糟糕的设计,部分原因是一个非常相似的模式的基准。压力测试在表中填充了可以缓存的数据。插入速率不能超过每秒7个实体。这是因为RAID条带化磁盘以满容量运行。规范化属性等导致 太多了 随机磁盘命中数。

        2
  •  0
  •   Renzo    9 年前

    编辑日期:

    考虑到必须执行的查询,我认为最好的做法是:

    1. 删除索引 entityId ;
    2. 将所有三个属性声明为主键(按顺序 entityId, attributeId, valueId ,而不引入显式(代理)主键。

    主键声明将导致在 实体ID,属性ID,值ID .

    这有两个效果:

    1. 可以减少由于缺少主键而导致的问题(有关问题的示例,请参见例如 this ),和
    2. 它将加快第一类查询的速度( select attributeId, valudId from propertyAssign where entityId=x ),因为访问计划只能使用索引来给出查询结果。