【问题标题】:How to represent many similar attributes of an entity in a database?如何在数据库中表示一个实体的许多相似属性?
【发布时间】:2012-11-16 22:47:23
【问题描述】:

假设我正在建立一个关于汽车的网站。汽车实体有很多类似枚举的属性:

  • 变速箱(手动/自动)
  • 燃料(汽油/柴油/生物乙醇/电力)
  • 车身风格(轿跑车/轿车/敞篷车/...)
  • 空调(无/简单/双区)
  • 外观颜色(黑/白/灰/蓝/绿/...)
  • 内饰颜色(黑/白/灰/蓝/绿/...)

这些属性的列表将来可能会发生变化。在数据库中建模它们的最佳方法是什么?我可以想到以下选项,但无法真正决定:

  • car 表中的字段与枚举值一起使用
    • 以后很难添加更多列,可能是最快的
  • 使用car 表中的字段,这些字段是引用查找表的外键
    • 以后很难添加更多列,有点慢
  • 为存储可能值的每个属性创建单独的表,并创建另一个表来存储汽车和属性值之间的连接
    • 以后容易添加更多可能的值,甚至更慢,似乎太复杂了

【问题讨论】:

  • Google for EAV:实体属性值。 (又名史密斯和史密斯)
  • @wildplasser:谢谢,这以一种非常简洁的方式解决了问题。也许你应该添加一个我可以投票的答案。
  • 不,我不会。太琐碎了。
  • 请注意,虽然@BillKarwin 是数据库设计方面的权威,但他也因讨厌 EAV 模型而闻名。

标签: sql database postgresql database-design entity-attribute-value


【解决方案1】:

理想的情况是创建一个关系数据库。 DB 中的每个表都应该由一个类表示,就像在 hibernate 中一样。您应该为汽车制作 2 张桌子。一个用于内部,一个用于汽车外部。如果您想添加额外的功能,您只需添加更多列。

【讨论】:

  • 据我所知,当表很大时添加更多列可能会导致严重的性能问题。
  • @BotondBalázs 只要您正确使用查询并拥有正确的索引,具有大型数据集的宽表就可以了。加入许多大表同样可能是一个性能问题
  • @Cez:你是对的,这些连接将比添加列更频繁地发生。看来我会采用宽表方法。
【解决方案2】:

现在这是一个(非常基本的)EAV 模型:

DROP TABLE IF EXISTS example.zvalue CASCADE;
CREATE TABLE example.zvalue
        ( val_id SERIAL NOT NULL PRIMARY KEY
        , zvalue varchar NOT NULL
        , CONSTRAINT zval_alt UNIQUE (zvalue)
        );
GRANT SELECT ON TABLE example.zvalue TO PUBLIC;

DROP TABLE IF EXISTS example.tabcol CASCADE;
CREATE TABLE example.tabcol
        ( tabcol_id SERIAL NOT NULL PRIMARY KEY
        , tab_id BIGINT NOT NULL REFERENCES example.zname(nam_id)
        , col_id BIGINT NOT NULL REFERENCES example.zname(nam_id)
        , type_id varchar NOT NULL
        , CONSTRAINT tabcol_alt UNIQUE (tab_id,col_id)
        );
GRANT SELECT ON TABLE example.tabcol TO PUBLIC;

DROP TABLE IF EXISTS example.entattval CASCADE;
CREATE TABLE example.entattval
        ( ent_id BIGINT NOT NULL
        , tabcol_id BIGINT NOT NULL REFERENCES example.tabcol(tabcol_id)
        , val_id BIGINT NOT NULL REFERENCES example.zvalue(val_id)
        , PRIMARY KEY (ent_id, tabcol_id, val_id)
        );
GRANT SELECT ON TABLE example.entattval TO PUBLIC;

顺便说一句:这是为支持系统目录而定制的;您可能需要进行一些更改。

【讨论】:

    【解决方案3】:

    这确实是此 dba.SE 帖子的副本:

    https://dba.stackexchange.com/questions/27057/model-with-variable-number-of-properties-of-different-types

    使用 hstore、json、xml、EAV 模式……请参阅我在那篇文章中的回答。

    【讨论】:

      【解决方案4】:

      根据查询的数量和数据库的大小,您可以:

      1. 制作宽桌
      2. 创建一个属性表和一个 car_attributes 表,其中:汽车 -> car_attributes -> 属性

      #1 由于连接较少,查询会更快、更容易,但 #2 更灵活

      【讨论】:

      • 如果我没记错的话,这是 cmets 中建议的 EAV 模式 @wildplasser。
      【解决方案5】:

      这取决于您需要支持的管理 UI:

      • 如果有一个接口来管理例如传输类型,您应该将它存储在一个单独的实体中。 (您的选择 3)
      • 如果没有这样的接口,最好存储类似的可枚举类型值。当您需要另一个(例如用于传输的“半自动”)时,您只需在 DB 模式中添加它,事实上这将是最容易支持和最快执行的

      【讨论】:

        【解决方案6】:

        我将创建创建表 CarAttributes 具有列 AttributeID、CarID、PropertyName、PropertyValue。 当返回 reslut 集时,我们将其保存在 IDictionary 中。 它将允许您根据需要添加任意数量的行,而无需添加新列。

        【讨论】:

          猜你喜欢
          • 2011-01-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-01
          • 1970-01-01
          • 2023-03-09
          相关资源
          最近更新 更多