【问题标题】:Implementing an efficient system of "unread comments" counters实施有效的“未读评论”计数器系统
【发布时间】:2010-10-01 23:18:05
【问题描述】:

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

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

你的经验如何?对于这类问题,或许已经形成了很好的解决方案?

【问题讨论】:

    标签: sql database database-design database-schema


    【解决方案1】:

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

    下一步:衡量性能! “衡量就是知道。”响应时间是多少?服务器的负载是多少?只要性能是可以接受的,保持模式和查询简单。如果不是绝对必要,请不要牺牲可维护性:您的继任者稍后会感谢您。

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        我不认为典型的标准化方法会给您带来低效的查询。假设您有一个表 article_comments 与 PK (article_id, comment_id) 和另一个表 comments_seen_by_user 与 PK (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 可能找到的更好的查询计划。

        您是否尝试过,并发现性能不佳?如果是这样,我的第一个猜测是你有一段时间没有VACUUMed。否则,我对每页文章数量或每篇文章 cmets 的估计一定是错误的——在这种情况下,请更新详细信息。

        【讨论】:

          【解决方案4】:

          我将第二次 j_random_hacker 的回答,只是我会避免将 article_id 存储在 cmets_seen_by_user 表中,因为每条评论的 comment_id 应该是全局唯一的。此外,PostgreSQL 中的 3 维(以及较小程度的 2 维)索引仍然很慢,因此请尽量避免使用它们。

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

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

          【讨论】:

            【解决方案5】:

            我同意采用标准化方法,看看是否可行。通常我应该。但是,您也可以在“评论”表上使用一些 INSERT 触发器,它会更新基本(即文章)表中的评论计数器。这取决于该网站的使用情况:如果 cmets 主要被读取(与添加 cmets 相比),则基于触发器的方法的开销应该会迅速摊销。如果它是一个评论负载很高的网站,这可能会影响性能。

            当您有一些合理的使用配置文件时,我会选择一个简单的规范化表结构并添加其他优化。

            【讨论】:

            • 您的触发器需要更新表中的 nUsers 行,其 PK 为 (user_id, article_id)(或某些变体),因为每个用户的评论查看历史都是独立的。不过还是可以的。
            猜你喜欢
            • 1970-01-01
            • 2011-08-06
            • 2016-02-22
            • 2022-11-13
            • 2014-05-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多