2012-11-27 54 views
0

在我的网站我有一个论坛,你可以启动一个线程,回应一个,删除自己的帖子,报告他人的信息等简单的查询与简单的数据库

我决定做一个抽象和创建一个名为activity的表,它将存储user_id,time(每个活动都有相同的字段)以及活动类型(线索,响应,报告,删除)和(对应于相应表的id) 。

开始时,这似乎是一个好主意,因为它有助于避免冗余,并且可以更容易查找某个用户完成的操作,而无需询问每个表。但与此同时,这种抽象会导致更复杂的查询(例如几乎每个简单的查询都必须使用INNER JOIN),现在我遇到了更复杂的查询问题。

所以我的问题是:我做出了正确的决定吗?即使它导致非常昂贵的查询,在真实生活环境中如何拥有一个完美的数据库如此重要?

+1

”正常化,直到它伤害,反规范化,直到它工作。“ –

回答

1

关系数据库系统的要点是关联数据(通过在正确的表中分隔实体),通过这样做来引入连接。这是正常的,也是一种很好的数据库设计技术

很多数据库初学者试图避免连接并添加来自各个实体的属性,以避免必须进行INNER连接,但这不是一种适当的技术,并且长期来说会咬你。加入是有原因的,应该在需要关联数据时使用。

在你的例子中,你本质上是创建一个“日志”文件。应用程序中的活动仅仅是用户正在做的事情的日志。问问你自己,一篇文章日志,一份报告日志,一份删除日志,一份日志,还有许多日志表或者一个带有referenceID的简单日志表,用户发起了什么活动(这个实际上是FK)。答案是你想要一个包含外键的日志表让你知道用户发起了什么(删除,添加,标志等)。

你想问自己的问题是,为什么当用户只是想要获取这些数据时显示活动信息。您可以随时保持这些数据正常化,但只在需要时才选择。我不明白你为什么加入这个活动表。

+0

是的,“这不是一个合适的技术,并且会长期咬你”,我想这是真的。这就像在优秀设计和简单性之间取回数据一样,在这种情况下,第一种可能会获胜。 为了回答你的问题:在活动表中,每个活动的'time'和'user_id'被存储,所以如果我想向用户展示它,我必须使用'INNER JOIN'。 无论如何,谢谢你的回答! – federicot

1

我想我会朝着与3 - 5年前相同的方向前进,但现在我会倾向于采用更简单,更平坦的数据库设计来描述您所描述的活动,而不是采用更标准化的方法。

我对CQRS和Task Driven UI的使用和理解确实帮助我意识到这一点 - 尽管它可能与您的情况无关。

本质上,我用来优化我的数据库,以便插入,更新和删除非常高效,但这会导致连接很多表以进行简单选择。问题是80%的时间,用户想要选择。因此,优化我的数据库结构,以确保用户在大多数情况下所做的工作确实有助于提高应用程序的整体性能,并且以我的观点来看,系统的维护和可扩展性。

我对你的应用程序以及你想做什么做了一些假设,但对我而言,一个活动表听起来像是可以从队列中提供并由单独的工作进程/线程构建的东西这是监视工作项的队列。当找到这些工作项目(命令)时,工作进程将平整数据并更新适当的活动表。当你去查询你的活动表时,你基本上会做一个简单的SELECT * FROM ACTIVITY(尽管我不建议SELECT *查询 - 命名你的列)。因此,您可以在插入/更新活动表格时发挥作用,但您的选择表现非常好。

我希望这会有所帮助。

1

我不确定你的问题是什么你的目的是分裂所有活动的共同特征,以及复杂查询给你带来麻烦的方式。

活动类型(线程,响应,报告,删除)的描述看起来像是类型和子类型的经典案例,也就是类和子类。这种情况有两种经典设计模式,称为单表继承和类表继承。这两种设计模式都有标签。还有另一种设计模式,即共享主键,可用于与类表继承一起使用。

从STI到CTI的转变确实涉及到一些表格分解,它与您描述的分解类似。 SPK的使用避免了每个专用子类表需要单独的id字段,并且也避免了对单独类型字段的需要。这可能会导致比您最终挣扎的查询更简单的查询。没有看到这些查询,这是不可能知道的。

值得注意的是,从获得符合任何标准正常形式2NF到5NF的意义上来说,这种分解不是“标准化”。但是这些正常的形式关注更新的简单性,而不是简单的查询。

一个好的设计是考虑到数据将被使用的方式。有时候我们会一路学习。我不知道什么是完美的设计。我认为我们总是参与权衡。 “