2010-05-27 246 views
7

我有意见存储表格,注释可以来自其他用户或其他个人资料,其是在此应用程序独立的实体。数据库最佳实践

我原来的想法是,该表将同时拥有USER_ID和PROFILE_ID领域,因此,如果用户提交一个评论,它给USER_ID离开PROFILE_ID空白

这是正确的,错误的,有没有更好的办法?

回答

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

如果评论是一般性的几个对象,你可以创建一个表中的每个对象:

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

然后,你不必在你的意见表中的任何空列。它还可以使未来轻松添加新的评论源对象,而无需触摸评论表。

+0

+ 1为正确的规范化技术 – DancesWithBamboo 2010-05-27 06:23:41

+0

我喜欢这个解决方案,但对评论者或评论者类型的评论做一个简单的过滤将需要一个连接。 – cherouvim 2010-05-27 06:33:41

+0

的确如此 - 但是一个连接是一个小缺点,并且总是可以为此创建一个View或Stored Procedure,因此每次需要获取该数据时都不必考虑连接。 – becquerel 2010-05-27 06:49:16

3

另一种方式来解决是始终非规范化(副本)上评论的留言者的姓名,还通过类型和id字段存储参考回到评议。这样你就有了一个统一的评论表,你可以快速搜索,排序和修剪。缺点是评论与其所有者之间没有任何真正的FK关系。

+0

迄今为止提到的方法中,我更喜欢这一个。是的,没有真正的外键关系;这总是会成为一个缺点,但很少有Web应用程序担心这一点!这是最容易扩展的方式,不会创建存储类似信息的许多不同表格。 – 2010-05-27 06:17:02

+0

我不明白。你是说,存储一个评论者名字的副本,但没有FK? – Tim 2010-05-27 06:22:12

+0

@ user270797:评论数据已在表格中。应该将评论者的数据(姓名,电子邮件等)复制(非规范化)在评论表上以便于访问。这种解决方案在某些情况下确实有意义。 – cherouvim 2010-05-27 06:29:00

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 , ...) 

然后在你的应用程序,当用户或配置文件,可以交替使用,可以参考的登录ID的任何地方。

+1

+1这是我开始写的解决方案。请参阅http://www.slideshare.net/billkarwin/practical-object-oriented-models-in-sql中的* Polymorphic Associations * – 2010-05-27 06:59:50

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) 
);