0

在我的网站上,我有一个论坛,您可以在其中发起话题、回复话题、删除您的帖子、举报他人的帖子等。

我决定进行抽象并创建一个名为的表,该表activity将存储user_id, time(每个活动共有的字段)和活动类型(线程、响应、报告、删除)和effective_idid对应于各自的桌子)。

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

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

4

4 回答 4

1

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

我对 CQRS 和任务驱动 UI 的使用和理解确实帮助我意识到了这一点——尽管它可能与您的情况无关。

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

我正在对您的应用程序以及您正在尝试做的事情做出一些假设,但是对我来说,活动表听起来像是可以从队列中提供并由监视队列的单独工作进程/线程构建的东西对于工作项。当找到这些工作项(命令??)时,工作进程将展平数据并更新适当的活动表。当你去查询你的活动表时,你基本上是在做一个简单的SELECT * FROM ACTIVITY(虽然我不推荐SELECT *查询——命名你的列)。所以你在插入/更新你的活动表时受到了打击,但你的选择表现很棒。

我希望这有帮助。

于 2012-11-27T20:20:27.340 回答
1

关系数据库系统的全部意义在于关联数据(通过在正确的表中分离实体),这样做可以引入连接。这是正常的,也是一种很好的数据库设计技术。

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

在您的示例中,您实质上是在创建一个“日志”文件。应用程序上的活动只是用户正在做什么的日志。问问自己,什么会更好,一个日志用于帖子,一个日志用于报告,一个日志用于删除,一个日志用于多个日志表或一个简单的日志表,其中包含关于用户发起的活动的 referenceID(这实际上是一个FK)。答案是您需要一个包含外键的日志表,让您了解用户启动的内容(删除、添加、标志等)。

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

于 2012-11-27T20:14:58.020 回答
1

从您的问题中,我不确定您拆分所有活动的共同特征的目的是什么,也不确定复杂查询以何种方式给您带来麻烦。

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

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

值得注意的是,这种分解不是“规范化”,因为它符合任何标准范式 2NF 到 5NF。但是这些正常形式关注的是更新的简单性,而不是查询的简单性。

考虑到数据的使用方式,进行了良好的设计。有时我们会在此过程中学到这一点。我不知道完美的设计是什么样的。我认为我们总是在权衡取舍。

于 2012-11-28T02:46:28.293 回答
0

您是否考虑过非规范化数据库?在这里查看更多信息:http ://en.wikipedia.org/wiki/Denormalization 。

于 2012-11-27T20:14:33.490 回答