数据库最佳实践

时间:2010-05-27 06:02:07

标签: database polymorphic-associations

我有一个存储评论的表,评论可以来自其他用户,也可以来自此应用中独立实体的其他个人资料。

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

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

5 个答案:

答案 0 :(得分: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。

答案 1 :(得分:4)

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

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

然后您的评论表中不必有任何空列。它还可以在将来添加新的注释源对象,而无需触及注释表。

答案 2 :(得分:3)

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

答案 3 :(得分: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"

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

答案 4 :(得分: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)
);