7

我有一个存储评论的表,评论可以来自另一个用户,也可以来自另一个配置文件,它们是这个应用程序中的独立实体。

我最初的想法是该表将同时具有 user_id 和 profile_id 字段,因此如果用户提交评论,它会给 user_id 留下 profile_id 空白

这是对还是错,有更好的方法吗?

4

5 回答 5

5

无论是最佳解决方案,恕我直言,不仅取决于表格,还取决于应用程序中其他地方的使用方式。

假设评论都与某个其他对象相关联,假设您从该对象中提取所有评论。在您提出的设计中,提取所有注释只需要从一个表中进行选择,这是有效的。但这是提取评论而不提取有关每个评论的发布者的信息。也许您不想显示它,或者它们已经缓存在内存中。

但是,如果您必须在检索评论时检索有关海报的信息怎么办?然后你必须加入两个不同的表,现在结果记录集被很多 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。

于 2010-05-27T06:54:41.317 回答
4

如果注释对于多个对象是通用的,您可以为每个对象创建一个表:

user_comments (user_id, comment_id)
profile_comments (profile_id, comment_id)

然后,您的评论表中不必有任何空列。它还将使将来添加新的评论源对象变得容易,而无需触及评论表。

于 2010-05-27T06:08:24.970 回答
3

另一种解决方法是始终对评论中的评论者名称进行非规范化(复制),并通过类型和 id 字段将引用存储回评论者。这样您就有了一个统一的评论表,您可以在其中快速搜索、排序和修剪。缺点是评论与其所有者之间没有任何真正的 FK 关系。

于 2010-05-27T06:11:52.263 回答
1

过去,我使用了一个集中的注释表,并为它所引用的 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"

这确保您可以在不创建冗余表的情况下扩展具有注释的对象数量。

于 2010-05-27T06:19:04.753 回答
0

这是另一种方法,它允许您通过外键维护引用完整性,集中管理,并使用标准数据库工具(如索引)提供最高性能,如果您确实需要,还可以使用分区等:

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)
);
于 2017-12-28T02:56:53.770 回答