创建论坛灯泡(未读)系统的最有效方法是什么?

时间:2010-09-29 15:29:38

标签: php mysql forum

好的,在50号公路上又是一个有趣的问题。

我们希望实现一个真正的论坛灯泡系统,其中用户未读的帖子(在用户的帐户创建之后)显示为未读,直到该状态被清除或用户读取它们为止。

我们认为最好和最简单的方法是实现未读消息表。

列是:user_idboard_idthread_idpost_idtimestamphidden

这对于查看每个用户未读(并链接到它们)的哪些板/线程/帖子非常有效且非常快,但是即使只有一个SQL查询,用户发布到论坛的速度也很慢正在运行:

INSERT IGNORE INTO `forums_lightbulb` SELECT `id`,'x','x','x',UNIX_TIMESTAMP(),0 FROM `users`

我确定这是拥有3065个用户帐户的结果。我怎样才能加快这个过程?我宁愿让系统保持尽可能实时。

重要提示:请将您的答案限制在共享托管环境中,无需额外预算。我们仅限于PHP和MySQL 5.1.53-log

4 个答案:

答案 0 :(得分:10)

PHPBB做的是一种非常快速的方法。它保留了一个表,用于标记每个线程和每个论坛的最后一次是用户打开它的时间。并使用它来确定是否有未读消息。它允许用户*主题+用户*论坛存储使用方案,同时允许使用非常简单和快速的查询进行检查。

您可以从数据库结构中看到它的工作原理。

# Table: 'phpbb_forums_track'
CREATE TABLE phpbb_forums_track (
    user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    forum_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    mark_time int(11) UNSIGNED DEFAULT '0' NOT NULL,
    PRIMARY KEY (user_id, forum_id)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;

# Table: 'phpbb_topics_track'
CREATE TABLE phpbb_topics_track (
    user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    topic_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    forum_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    mark_time int(11) UNSIGNED DEFAULT '0' NOT NULL,
    PRIMARY KEY (user_id, topic_id),
    KEY topic_id (topic_id),
    KEY forum_id (forum_id)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;

答案 1 :(得分:4)

很抱歉,但问题中提出的解决方案是不可扩展的设计。

我在here上调查了这个问题,对它进行了不错的讨论(在我出现之前)。看看那里。

在您的情况下,存储U * M记录以跟踪“未读”帖子,其中U是用户数,M是消息数,将非常非常快速地失控。这是因为它的最佳效率需要所有用户阅读每条消息(大多数用户并不关心所有内容,因为论坛上的大多数内容都是噪音)。平均情况下,可能有20%的用户已经阅读了100%的帖子,但80%的用户已经阅读了近0%的帖子,从未阅读过其余的帖子。这意味着您被迫存储0.8 * U * M,而U和M仅在几何上增加。没有多少索引可以解决这个问题。

之前的@ will-hartung答案具有更高效的方法。

我发现这已经很老了,我希望你能在此期间找到更好的解决方案。

答案 2 :(得分:2)

这是最有效的方式:

  1. 有一个名为read_threads的表,用于存储thread_iduser_id
  2. users表中有一个名为mark_read_date的列,用于存储用户点击论坛中mark all threads read链接的日期
  3. 为了确定是否读取了一个帖子,您的查询将检查它是否在read_threads表中,或者它的last_post_date(最后一个帖子的日期)是否更早而不是users mark_read_date
  4. 当用户点击论坛中的read_threads链接时,同时删除mark all threads read表格中的所有行也很重要。

答案 3 :(得分:1)

阅读:

insert into read_articles(user_id, article_id);

显示:

SELECT a.*, r.user_id FROM articles a 
LEFT OUTER JOIN read_articles r ON (a.article_id = r.article_id and r.user_id = $user_id)
WHERE (article_filter, like forum or thread id, or whatever)

在结果集上,如果user_id不为null,则他们已阅读该文章。否则,他们没有。

适当的索引。服务员用饼干和果酱加热。