实施有效的“未读评论”计数器系统

时间:2009-01-17 09:45:55

标签: sql database database-design database-schema

我正在尝试为以下问题找到最佳解决方案:需要设计一个数据库(基于postgres),其中包含触发器和计数器系统,这将形成一个高效查询,更新和存储有关“页面上显示的每篇文章(或博客条目,或类似的)中有多少未读评论的信息'。

每个解决方案都有一些严重的缺点,无论是在查询,还是存储或更新部分。即它需要太多的存储空间,或者需要太多的更新,或者需要过多的查询。

你的满意度如何?也许这种问题已经形成了很好的解决方案?

5 个答案:

答案 0 :(得分:8)

我会尽可能简化架构,因此查询将尽可能简单。这通常也具有最低的存储要求。当然,设置索引以支持此查询。

下一步:衡量表现! “衡量就是知道。”什么是响应时间?服务器上的负载是多少?只要性能可以接受,就要保持架构和查询的简单性。如果不是绝对必要的话,不要牺牲可维护性:你的继任者将在以后感谢你。

如果性能确实存在问题,请查看您正在为应用程序使用的框架的缓存功能。不执行查询总是比执行优化查询更快。

答案 1 :(得分:4)

如果你真的没有在资源范围内成功,也许你必须调整用户体验。也许存储上次访问线程的日期就足够了。

答案 2 :(得分:4)

我不相信典型的规范化方法会让您的查询效率低下。假设您有一个PK article_comments的表(article_id, comment_id)和另一个PK comments_seen_by_user的表(user_id, article_id, comment_id)。您需要做的就是,对于页面上列出的每篇文章:

SELECT count(*) FROM article_comments ac
WHERE article_id = ?                -- Parameter
AND NOT EXISTS (
    SELECT 1 FROM comments_seen_by_user csbu
    WHERE csbu.user_id = ?          -- Parameter
    AND   csbu.article_id = ac.article_id
    AND   csbu.comment_id = ac.comment_id
)

如果你在一个页面上显示20篇文章,你将运行上述查询20次,每次运行将使用索引从article_comments中拉出10-20行,并且子查询测试只是另一个索引扫描comments_seen_by_user,所以总而言之,您可能需要执行20 *(20 * 2)= 800个索引查找来显示给定页面。对现代数据库而言,这不是什么难事。我可能会忽略PostgreSQL可能找到的更好的查询计划。

你试过这个,发现性能想要吗?如果是这样,我的第一个猜测就是你有一段时间没有VACUUM。否则,我必须得到我对每页文章数量或每篇文章评论的估计错误 - 请在这种情况下更新详细信息。

答案 3 :(得分:1)

我将第二个j_random_hacker的回答,只是我避免将articles_id存储在comments_seen_by_user表中,因为comment_id对于每个注释应该是全局唯一的。在PostgreSQL中,3维(和2-d到较小程度)的索引仍然很慢,所以尽量避免它们。

围绕user_id,comment_id值表没有很好的方法来存储有关读取注释的信息,只需确保它具有唯一索引。这样的表中几千万行对PostgreSQL来说完全没问题,只要它能将索引保存在内存中。您可以通过查询系统表来跟踪索引大小(磁盘上8KB页面的数量):

select relname,relpages from pg_class where relname='comments_seen_by_user_pkey';

答案 4 :(得分:0)

我同意采用标准化的方法,看看它是否有效。通常我应该。但是,您还可以在“注释”表上使用一些INSERT触发器,该表更新基本(即文章)表中的注释计数器。这取决于该网站的使用情况:如果评论主要是读取(与添加评论相比),基于触发器的方法的开销应该快速摊销。如果它是一个评论负荷较高的网站,这可能会导致性能下降。

如果你有一些合理的使用情况,我会选择一个简单的,规范化的表结构并在以后添加其他优化。