Определение непрочитанных предметов на форуме - PullRequest
4 голосов
/ 05 февраля 2009

Используя PHP и MySQL, я пытаюсь создать систему форумов. Я хочу знать, как я могу настроить его так, чтобы, когда пользователь читает запись на форуме, он отображался как прочитанный JUST для этого пользователя, независимо от того, на каком форуме он находится, до тех пор, пока кто-то другой не опубликует его.

В настоящее время для каждой темы у меня есть таблица с PostID, и в ней есть UserID, который ее опубликовал, ThreadID, на который она ссылается, фактическое сообщение (в виде текста), а затем дата / время публикации.

Для списка тем в каждом форуме есть идентификатор потока (первичный ключ), имя потока, идентификатор форума, которому он принадлежит, NumPosts, NumViews, LastPostDateTime и CreateDateTime. Любая помощь?

Ответы [ 7 ]

8 голосов
/ 05 февраля 2009

Традиционным решением является таблица соединений что-то вроде:

CREATE TABLE topicviews (
    userid INTEGER NOT NULL,
    topicid INTEGER NOT NULL,
    lastread TIMESTAMP NOT NULL,
    PRIMARY KEY (userid, topicid),
    FOREIGN KEY (userid) REFERENCES users(id),
    FOREIGN KEY (topicid) REFERENCES topics(id)
);

последнее обновление обновляется каждый раз, когда читается тема. При отображении списка тем, если themes.lastupdated> topicviews.lastread, появляются новые сообщения.

Традиционное решение - мусор, который убьет вашу базу данных! Не делай этого!

Первая проблема заключается в том, что запись в каждом представлении темы вскоре поставит сервер баз данных на колени на загруженном форуме, особенно в таблицах MyISAM, которые имеют только блокировки на уровне таблиц. (Не используйте таблицы MyISAM, используйте InnoDB для всего, кроме полнотекстового поиска).

Вы можете немного улучшить эту ситуацию, потрудившись писать в последний раз, когда в теме читаются действительно новые сообщения. Если topic.lastupdated

Вторая проблема - комбинаторный взрыв. Скоро складывается по одной строке на пользователя на тему: всего тысяча пользователей и тысяча тем, и у вас есть потенциально миллион строк для просмотра тем!

Вы можете немного улучшить эту ситуацию, ограничив количество тем, запоминаемых для каждого пользователя. Например, вы можете удалить любую тему из таблицы представлений, когда она станет старше определенного возраста, и просто предположить, что все старые темы «прочитаны». Обычно для этого требуется выполнить очистку в фоновом режиме.

Другие, менее интенсивные подходы включают в себя:

  • хранит только одно последнее чтение за форум
  • хранит только одно время последнего посещения для каждого пользователя на всем сайте, которое будет отображаться как «новые» только обновленные данные с момента предыдущего посещения (сеанса) пользователя
  • вообще не хранит последнюю прочитанную информацию, но включает время последнего обновления в самом URL темы. Если браузер пользователя недавно видел эту тему, он запомнит URL и пометит его как посещенный. Затем вы можете использовать CSS для стилизации посещенных ссылок как «тем, не содержащих новых сообщений».
3 голосов
/ 05 февраля 2009

Может храниться в другой таблице UserID, threadID, LastReadDateTime, когда пользователь читает этот поток.

if (LastPostDateTime > LastReadDateTime) you got an unread post.

К сожалению, у вас большие накладные расходы, при каждом чтении у вас будет запись.

2 голосов
/ 05 февраля 2009

Общие идеи здесь верны, но они упустили из виду некоторые очевидные решения проблемы масштабируемости.

@ bobince: Вторая проблема - комбинаторный взрыв. Скоро складывается одна строка на пользователя на тему: всего тысяча пользователей и тысяча тем, и у вас есть потенциально миллион строк для просмотра тем!

Вам не нужно хранить запись в таблице "topicviews", если кто-то никогда не просматривал эту ветку. Вы бы просто отобразили тему с непрочитанными сообщениями, если возвращается ноль ИЛИ время last_read составляет <время last_post. Это уменьшит этот «миллион» строк, возможно, на порядок. </p>

@ gortok: есть много способов сделать это, но каждый увеличивается по экспоненте, когда пользователь посещает сайт.

В этом случае вы архивируете форум после n-сообщений или n-недель и, когда блокируете, очищаете таблицу «topicviews».

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

Но, если честно? Вам, вероятно, не нужно беспокоиться о масштабируемости. Даже миллион строк на самом деле не так уж много.

1 голос
/ 06 февраля 2009

Вы можете просто использовать функциональность браузера пользователя и добавить последний пост в ссылку на тему, например: "thread.php? Id = 12 & lastpost = 122"

Используя в вашем CSS a: посещения, вы можете отображать сообщения, которые пользователь уже прочитал, отличные от тех, которые он не читал.

1 голос
/ 05 февраля 2009

Нет простого способа сделать это. Есть много способов сделать это, но каждый становится экспоненциально больше, когда пользователь посещает сайт. Лучшее, что вы можете сделать и при этом сохранить производительность, - это иметь временную метку и пометить все форумы, которые были обновлены с момента последнего посещения, как «непрочитанные».

0 голосов
/ 06 февраля 2017

Используется функционал браузера пользователя и добавляется идентификатор последнего сообщения в ссылке в ветке. После использования a: посещения в CSS вы можете отобразить все темы, которые не были прочитаны пользователем.

0 голосов
/ 05 февраля 2009

У Bobince есть много хороших предложений. Еще несколько потенциальных оптимизаций:

Напишите новое "это новое?" информация в memcached и в таблицу MySQL "ARCHIVE". Пакетное задание может обновить «настоящую» таблицу.

Для каждого пользователя сохраняйте флаг «все прочитано до $ date» (для случая, когда нажата кнопка «отметить все прочитанное»).

Когда публикуется что-то новое, снимите все флажки «это было прочитано» - это уменьшает количество «флагов», и таблица может быть просто (topic_id, user_id) - без отметок времени.

...