Каков наиболее эффективный способ создания системы "лампочка форума" (непрочитанная)?


Хорошо, еще одна интересная проблема на трассе 50.

Мы хотели внедрить настоящую систему освещения форума, в которой сообщения, непрочитанные пользователем (после создания учетной записи пользователя), отображаются как непрочитанные до тех пор, пока этот статус не будет снят или пока пользователь их не прочитает.

Мы решили, что лучший и самый простой способ сделать это - реализовать таблицу непрочитанных сообщений.

Столбцы являются: user_id, board_id, thread_id, post_id, timestamp, и hidden

Это работает очень хорошо и очень быстро для просмотра, какие доски/темы/сообщения непрочитаны (и ссылки на них) для каждого пользователя, однако для пользователя НЕВЕРОЯТНО медленно размещать сообщения на форуме, даже если выполняется только один SQL-запрос:

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

Я уверен, что это результат наличия 3065 учетных записей пользователей. Как я могу ускорить этот процесс? Я бы предпочел, чтобы система работала в режиме реального времени, насколько это возможно.

Важное примечание: Пожалуйста, ограничьте свои ответы средой общего хостинга без дополнительных бюджет. Мы ограничены PHP и MySQL 5.1.53-log

Author: Peter O., 2010-09-29

4 answers

То, что делает 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`;
 10
Author: Beanow, 2012-01-29 13:48:33

Извините, что говорю, но решение, предложенное в вопросе, является не поддающейся масштабированию конструкцией.

Я изучал эту проблему над здесь , в которой было приличное обсуждение (до того, как я появился). Взгляните туда.

В вашем случае хранение записей U*M для отслеживания "непрочитанных" сообщений, где U - количество пользователей, а M - количество сообщений, очень и очень быстро выйдет из-под контроля. Это связано с тем, что его максимальная эффективность требует, чтобы все пользователи читали каждое сообщение (и большинству пользователей все равно, так как почти все на форуме - это шум). В среднем, возможно, 20 % пользователей прочитали 100 % сообщений, но 80 % прочитали около 0 % сообщений и никогда не прочтут остальные. Это означает, что вы вынуждены хранить 0,8*U*M, при этом U и M только увеличиваются геометрически. Никакая индексация этого не исправит.

Предыдущий ответ @will-hartung имеет более эффективный подход.

Я вижу, что это довольно старое, и я надеюсь, что вы нашли тем временем лучшее решение.

 4
Author: Kaiden, 2017-05-23 11:46:34

Вот наиболее эффективный способ:

  1. есть таблица с именем read_threads, в которой хранятся thread_id и user_id
  2. есть столбец в таблице users под названием mark_read_date, в котором хранится дата, когда пользователь нажал на ссылку mark all threads read на вашем форуме
  3. чтобы определить, прочитан ли поток, ваш запрос проверит, находится ли он в таблице read_threads или его last_post_date (дата, когда в нем была сделана последняя запись) старше, чем users mark_read_date

Важно, чтобы вы также удалите все строки из таблицы read_threads, когда пользователь нажимает ссылку mark all threads read на вашем форуме.

 2
Author: inkd, 2015-06-12 19:25:19

При чтении:

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)

В вашем результирующем наборе, если идентификатор пользователя не равен нулю, значит, они прочитали статью. В противном случае они этого не сделали.

Индекс по мере необходимости. Подавать теплым с печеньем и джемом.

 1
Author: Will Hartung, 2010-09-29 15:42:05