我有一个存储评论的表,评论可以来自另一个用户,也可以来自另一个配置文件,它们是这个应用程序中的独立实体。
我最初的想法是该表将同时具有 user_id 和 profile_id 字段,因此如果用户提交评论,它会给 user_id 留下 profile_id 空白
这是对还是错,有更好的方法吗?
我有一个存储评论的表,评论可以来自另一个用户,也可以来自另一个配置文件,它们是这个应用程序中的独立实体。
我最初的想法是该表将同时具有 user_id 和 profile_id 字段,因此如果用户提交评论,它会给 user_id 留下 profile_id 空白
这是对还是错,有更好的方法吗?
无论是最佳解决方案,恕我直言,不仅取决于表格,还取决于应用程序中其他地方的使用方式。
假设评论都与某个其他对象相关联,假设您从该对象中提取所有评论。在您提出的设计中,提取所有注释只需要从一个表中进行选择,这是有效的。但这是提取评论而不提取有关每个评论的发布者的信息。也许您不想显示它,或者它们已经缓存在内存中。
但是,如果您必须在检索评论时检索有关海报的信息怎么办?然后你必须加入两个不同的表,现在结果记录集被很多 NULL 值污染(对于配置文件评论,所有用户字段都将为 NULL)。必须解析此结果集的代码也可能变得更加复杂。
就个人而言,我可能会从完全规范化的版本开始,然后在我开始看到性能问题时去规范化
该问题还有一个完全不同的可能解决方案,但这取决于它在域中是否有意义。如果应用程序中还有其他地方可以互换使用用户和海报怎么办?如果用户只是一种特殊的配置文件怎么办?然后我认为解决方案应该在用户/配置文件表中解决。例如(一些缩写的伪sql):
create table AbstractProfile (ID primary key, type ) -- type can be 'user' or 'profile'
create table User(ProfileID primary key references AbstractProfile , ...)
create table Profile(ProfileID primary key references AbstractProfile , ...)
然后,在您的应用程序中可以互换使用用户或配置文件的任何地方,您都可以引用 LoginID。
如果注释对于多个对象是通用的,您可以为每个对象创建一个表:
user_comments (user_id, comment_id)
profile_comments (profile_id, comment_id)
然后,您的评论表中不必有任何空列。它还将使将来添加新的评论源对象变得容易,而无需触及评论表。
另一种解决方法是始终对评论中的评论者名称进行非规范化(复制),并通过类型和 id 字段将引用存储回评论者。这样您就有了一个统一的评论表,您可以在其中快速搜索、排序和修剪。缺点是评论与其所有者之间没有任何真正的 FK 关系。
过去,我使用了一个集中的注释表,并为它所引用的 fk_table 提供了一个字段。
例如:
comments(id,fk_id,fk_table,comment_text)
这样您就可以使用 UNION 查询来连接来自多个来源的数据。
SELECT c.comment_text FROM comment c JOIN user u ON u.id=c.fk_id WHERE c.fk_table="user"
UNION ALL
SELECT c.comment_text FROM comment c JOIN profile p ON p.id=c.fk_id WHERE c.fk_table="profile"
这确保您可以在不创建冗余表的情况下扩展具有注释的对象数量。
这是另一种方法,它允许您通过外键维护引用完整性,集中管理,并使用标准数据库工具(如索引)提供最高性能,如果您确实需要,还可以使用分区等:
create table actor_master_table(
type char(1) not null, /* e.g. 'u' or 'p' for user / profile */
id varchar(20) not null, /* e.g. 'someuser' or 'someprofile' */
primary key(type, id)
);
create table user(
type char(1) not null,
id varchar(20) not null,
...
check (id = 'u'),
foreign key (type, id) references actor_master_table(type, id)
);
create table profile(
type char(1) not null,
id varchar(20) not null,
...
check (id = 'p'),
foreign key (type, id) references actor_master_table(type, id)
);
create table comment(
creator_type char(1) not null,
creator_id varchar(20) not null,
comment text not null,
foreign key(creator_type, creator_id) references actor_master_table(type, id)
);