【问题标题】:Optimal DB structure for additional fields entity附加字段实体的最佳数据库结构
【发布时间】:2010-09-25 22:59:59
【问题描述】:
我在数据库中有一个表(基于 Postgres),它就像面向对象编程中的超类。它有一个“类型”列,用于确定表中应该存在哪些附加列(子类属性)。但我不希望该表包含所有可能的列(所有可能类型的所有属性)。
所以我决定制作一个表,包含“key”和“value”列(即“filename”=“/file”或“some_value”=“5”),其中包含对象的任何可能属性,不包括在超类表中。并且还制作了一个相关表来包含可用的“键”值。
但是这种架构存在一个问题——“值”列默认应该是字符串数据类型,才能包含任何内容。但我不认为转换为字符串和从字符串转换是一个好的决定。绕过此限制的最佳方法是什么?
【问题讨论】:
标签:
sql
database
postgresql
entity-attribute-value
【解决方案1】:
您正在试验的设计是Entity-Attribute-Value 的变体,它带来了很多问题和低效率。对于您正在做的事情,这不是一个好的解决方案,除非作为最后的手段。
fall888 描述的更好的解决方案是:为每个子类型创建一个“子类型”表。如果您有有限数量的子类型,这没关系,这听起来像您所拥有的。然后,您的子类型特定属性可以具有数据类型,如果合适,还可以具有 NOT NULL 约束,如果您使用 EAV 设计,这是不可能的。
子类型表设计的一个剩余弱点是,您不能仅仅因为超类表中的主行说它应该存在就强制子类型表中存在一行。但这比 EAV 设计引入的弱点要温和一些。
编辑:关于您关于 cmets-to-any-entity 的其他信息,是的,这是一种非常常见的模式。当心一种被称为“多态关联”的损坏解决方案,这是许多人在这种情况下使用的一种技术。
【解决方案2】:
这样怎么样...每个子类型都有自己的数据库表。基础/超级表只有一个 varchar 列,其中包含子类型 DB 表的名称。然后你可以有这样的东西......
Entity
------
ID
Name
Type
SubTypeName (value of this column will be 'Dog')
Dog
---
VetName
VetNumber
etc
如果您不希望您的(子)表名称是基表中的 varchar 值,您也可以只拥有一个主键将在基表中的 SubType 表。
【解决方案3】:
唯一的解决方法(同时保留您的结构)是使用单独的表格:
create table IntProps(...);
create table StringProps(...);
create table CurrencyProps(...);
但我不认为这是个好主意……
【解决方案4】:
一种常见的方法是让键值表包含多个列,每个数据类型对应一个列,即 StringValue、DecimalValue 等。
只需知道您正在为不需要更改的数据库架构交易可查询性和性能。您还可以考虑 ORM 映射或对象数据库。
【解决方案5】:
您可以有一个按类型键/值表。可用表需要对特定键/类型对的可用性进行编码,以指向正确键入的键/值表。
然而,对于基于行的关系数据库来说,这似乎是一种非常低效的架构。
也许您应该看看面向列的关系数据库?
【解决方案7】:
关于用户能够向表中添加新字段:
我钦佩所有制作 cmets 的人。
几年前我曾经对这种东西感兴趣,但最近写的代码很少(除了一点点PHP和MYSQL)。
如果你想继续前进,我认为这很好——你最终可能会得到一些新的东西。
很抱歉给这个计划泼冷水 - 我很欣赏你的努力。我个人的信念是,如果你在这个方向上走得足够远,你最终会得到一个比 SQL 解释更多自然语言的系统。 (在 1970 年左右,SQL 实际上拼写为 Sequel,它实际上代表“结构化英语查询语言”,但在 1970 年代他们将其标准化之后——我想有人说 Oracle 是第一个商业实现,19079 年,“英语”得到了放弃了,因为我猜他们认为这只是英语的一小部分。
我在这方面已经筋疲力尽了,因为我还没有找到工作。如果没有一份轻松的工作来支付账单,我可以在其中尝试这些想法,那么专注于这个领域有点困难。
祝大家好运。
【解决方案8】:
抱歉,我在上面写了 19079,我指的是 1979 年。Oracle 获得了他们的第一份合同,为 CIA 编写数据库。