数据库设计-每次都存储状态还是计算状态?


17

假设我有一个关系数据库应用程序,一个“用户”对象和一个“消息”对象。现在,我想向该用户显示未读邮件的数量。

存档的最佳方法是什么?我是否在用户中引入一个字段并在用户收到消息时对其进行计数,并在他阅读消息时减少计数?还是我每次都执行查询以计算标记为未读的用户消息数?

我认为第一种方法更复杂且容易出错,但是会比第二种方法表现更好。

这通常是如何完成的,或者有什么更好的方法?


1
取决于许多因素:数据库是否已分区?您期望每用户多少行?您期望什么大小的数据库总数(或多少用户总数)?您期望每秒有多少个请求?所有这些都不一定是准确的,但是有些粗略的想法……
Omer Iqbal 2014年

10
+1这是一个经典的关系数据库问题。标准化还是不标准化?就是那个问题。架构中的t'是不是更难忍受残酷重复的吊索和箭,还是要抓住触发器,并通过雇用来终结它们?
罗斯·帕特森

我认为这是否不属于经典Rel。D b。问题,站点上应该已经有答案,应该以DUP的形式关闭,否则我们没有答案,应该将其保留为开放状态。
mattnz 2014年

Answers:


14

这通常是如何完成的,或者有什么更好的方法?

最好的方法是先在没有额外字段的情况下进行尝试,然后评估性能,如果结果确实太慢,则尝试进行优化。这可能意味着要使用额外的字段切换到第一种方法,但是您也应该考虑测试其他选项,例如,在邮件的组合字段(“未读”,“用户ID”)上放置一个额外的索引。


2
最好的方法是(首先使用较简单的方法)。首先,一般规则比具体规则要好。(+1虽然“测试!”。)
DougM

9

根据数据库理论的教科书解决方案是数据库中没有依赖于其他数据值的值,因为这些值是传递依赖项。具有基于其他字段的计算值的字段违反规范化,因为这会导致冗余信息。

但是,有时教科书所说的和实践中最实用的方法有所不同。计算每个浏览量的未读消息数可能是一个非常昂贵的操作。将数字缓存在user-table中会更好地提高性能。代价是数据库中可能存在不一致的地方:可能有可能删除,添加或读取一条消息而又不记得还要更新未读计数器。


4
可以通过在INSERT或上调整计数器的触发器轻松解决一致性问题DELETE。(或UPDATE,以说明邮件所有者的更改。)。一个好的DBMS将在同一事务中执行该操作并运行触发器,因此全部或全部不会发生。
Blrfl 2014年

4

潜在的问题是性能,但是您还没有性能问题。根据解决方案#1所选择的数据库,您可以做很多事情,包括建立索引,硬件,缓存等。这一切都取决于用户需要多长时间获取一次当前的未读消息数。这些选择中的许多不需要在应用程序端进行自定义编码,因此您可以更改代码或只需很少的代码即可实现它们。使应用程序的增长变得更加容易。

用户连接/登录后,一次从数据库中获取计数并不是一件坏事。您的应用程序是否会维护不断更新的邮件列表,例如电子邮件?从这里获取未读计数不需要再次访问数据库,而要获取新消息则无论如何都要进行数据库访问。

每次读取一条消息以标记IsRead时都要去数据库。一个字段就足够了,而无需重新计算另一个字段。

使用解决方案2(在字段/磁盘中保持计数)时,是否需要例程来在出现问题时定期重建/重新计算该字段?而且总是有问题。您是否要将所有这些包装在交易中?每次有人向他人发送消息时,消息是否会失败,因为由于用户表的锁定而无法更新接收用户的UnreadCount?还是要为此字段创建一个单独的表?


+1表示保持计数字段为最新状态时的性能问题
winkbrace 2014年

0

我这样做的方式是每次都执行查询,即您的第二种方法。只要确保您在消息表中的列上添加一个索引,该索引就可以作为用户表的外键以提高查询的性能。

然后像Doc所说的那样,测量这种方法的性能,然后您将能够知道是否需要采取不同的方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.