数据库最佳实践

问题描述 投票:7回答:5

我有一个存储注释的表,注释可以来自另一个用户,或者是另一个在此应用中是独立实体的配置文件。

我原来的想法是该表将同时具有user_id和profile_id字段,因此如果用户提交注释,则会给user_id留下profile_id为空

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

database polymorphic-associations
5个回答
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"

这可确保您可以扩展具有注释的对象数,而无需创建冗余表。


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。


4
投票

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

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

然后,您的注释表中不必包含任何空列。它还可以在将来轻松添加新的comment-source-objects而无需触及comments表。


3
投票

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


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)
);
© www.soinside.com 2019 - 2024. All rights reserved.