如何在数据库中表示一个实体的许多相似属性?
Posted
技术标签:
【中文标题】如何在数据库中表示一个实体的许多相似属性?【英文标题】:How to represent many similar attributes of an entity in a database? 【发布时间】:2012-11-16 22:47:23 【问题描述】:假设我正在建立一个关于汽车的网站。汽车实体有很多类似枚举的属性:
变速箱(手动/自动) 燃料(汽油/柴油/生物乙醇/电力) 车身风格(轿跑车/轿车/敞篷车/...) 空调(无/简单/双区) 外观颜色(黑/白/灰/蓝/绿/...) 内饰颜色(黑/白/灰/蓝/绿/...) 等这些属性的列表将来可能会发生变化。在数据库中建模它们的最佳方法是什么?我可以想到以下选项,但无法真正决定:
将car
表中的字段与枚举值一起使用
以后很难添加更多列,可能是最快的
使用car
表中的字段,这些字段是引用查找表的外键
以后很难添加更多列,有点慢
为存储可能值的每个属性创建单独的表,并创建另一个表来存储汽车和属性值之间的连接
以后容易添加更多可能的值,甚至更慢,似乎太复杂了
【问题讨论】:
Google for EAV:实体属性值。 (又名史密斯和史密斯) @wildplasser:谢谢,这以一种非常简洁的方式解决了问题。也许你应该添加一个我可以投票的答案。 不,我不会。太琐碎了。 查看我对***.com/questions/695752/…的回复 请注意,虽然@BillKarwin 是数据库设计方面的权威,但他也因讨厌 EAV 模型而闻名。 【参考方案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】:根据查询的数量和数据库的大小,您可以:
-
制作宽桌
创建一个属性表和一个 car_attributes 表,其中:汽车 -> car_attributes -> 属性
#1 由于连接较少,查询会更快、更容易,但 #2 更灵活
【讨论】:
如果我没记错的话,这是 cmets 中建议的 EAV 模式 @wildplasser。【参考方案5】:这取决于您需要支持的管理 UI:
如果有一个接口来管理例如传输类型,您应该将它存储在一个单独的实体中。 (您的选择 3) 如果没有这样的接口,最好存储类似的可枚举类型值。当您需要另一个(例如用于传输的“半自动”)时,您只需在 DB 模式中添加它,事实上这将是最容易支持和最快执行的【讨论】:
【参考方案6】:我将创建创建表 CarAttributes 具有列 AttributeID、CarID、PropertyName、PropertyValue。 当返回 reslut 集时,我们将其保存在 IDictionary 中。 它将允许您根据需要添加任意数量的行,而无需添加新列。
【讨论】:
以上是关于如何在数据库中表示一个实体的许多相似属性?的主要内容,如果未能解决你的问题,请参考以下文章
如何在我的 Graphql Schema 中表示 Neo4j 关系属性?
SQL - 确保在一组关键密钥对中表示的两个实体都存在于最终数据集中的有效方法