従来の解決策は、次のような結合テーブルです。
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)
);
トピックが読み取られるたびにlastreadが更新されます。トピックのリストを表示するときに、topics.lastupdatedが> topicviews.lastreadの場合、新しい投稿があります。
従来の解決策はごみであり、データベースを破壊します!しないでください!
最初の問題は、すべてのトピックビューに書き込むと、忙しいフォーラム、特にテーブルレベルのロックしかないMyISAMテーブルで、データベースサーバーがすぐにひざまずくということです。(MyISAMテーブルを使用しないでください。全文検索を除くすべてに、InnoDBを使用してください)。
トピックで実際に新しいメッセージが読み取られているときに、最後の読み取り時刻をわざわざ書き込むだけで、この状況を少し改善できます。topic.lastupdated <topicviews.lastreadの場合、値を更新しても何も得られません。それでも、頻繁に使用されるフォーラムでは、これは負担になる可能性があります。
2番目の問題は組み合わせ爆発です。トピックごとにユーザーごとに1行がすぐに追加されます。つまり、ユーザー数が1,000、トピック数が1,000であり、保存するトピックビュー行が100万になる可能性があります。
ユーザーごとに記憶されるトピックの数を制限することで、この状況を少し改善できます。たとえば、特定の年齢より古くなったトピックをビューテーブルから削除し、すべての古いトピックが「既読」であると想定することができます。これには通常、バックグラウンドでクリーンアップタスクを実行する必要があります。
その他のそれほど集中的でないアプローチには、次のものがあります。
- フォーラムごとに最後の読み取り時間を1つだけ保存します
- サイト全体でユーザーごとに1回の最終訪問時間のみを保存します。これは、ユーザーの前回の訪問(セッション)以降に更新されたもののみを「新規」として表示します。
- 最終読み取り情報はまったく保存されませんが、トピックのURL自体に最終更新時刻が含まれます。ユーザーのブラウザが最近トピックを見た場合、URLを記憶し、訪問済みとしてマークします。次に、CSSを使用して、訪問したリンクを「新しいメッセージを含まないトピック」としてスタイル設定できます。