テーブル
記事のテーブルがあると仮定しましょう:
CREATE TABLE articles
(
id integer PRIMARY KEY,
last_update timestamp NOT NULL,
...
);
ユーザーは記事をブックマークできます:
CREATE TABLE bookmarks
(
user integer NOT NULL REFERENCES users(id),
article integer NOT NULL REFERENCES articles(id),
PRIMARY KEY(user, article),
last_seen timestamp NOT NULL
);
実装する機能
私が今やりたいことは、ユーザーが最後に見た後に更新された記事についてユーザーに知らせることです。システム全体へのアクセスは、Web インターフェイスを介して行われます。ページが要求されるたびに、システムは更新された記事についてユーザーに通知する必要があるかどうかを確認する必要があります (SO のページ上部の通知バーと同様)。
質問
上記の両方のテーブルに数千万行が含まれている場合、そのような機能の最適かつ最も効率的な実装は何ですか?
私の解決策 #1
次のような単純な結合を行うことができます。
SELECT ... FROM articles, bookmarks WHERE bookmarks.user = 1234
AND bookmarks.article = articles.article AND last_seen < last_update;
ただし、この JOIN を実行すると、ユーザーが多くのブックマークされた記事を持っている場合 (思ったよりも頻繁に発生する可能性があります)、特にデータベース (私の場合は PostgreSQL) が主キーのインデックスをトラバースする必要がある場合、コストがかかるのではないかと心配しています。articles
ブックマークされたすべての記事の。また、last_seen < last_update
述語は、ディスク上の行にアクセスした後にのみチェックできます。
私の解決策 #2
別の方法はより難しいですが、私の場合はより良いかもしれません。これには、通知列によってブックマーク テーブルを拡張することが含まれます。
CREATE TABLE bookmarks
(
user integer NOT NULL REFERENCES users(id),
article integer NOT NULL REFERENCES articles(id),
PRIMARY KEY(user, article),
last_seen timestamp NOT NULL,
notify boolean NOT NULL DEFAULT false
);
CREATE INDEX bookmark_article_idx ON bookmarks (article);
記事が更新されるたびに、この記事をブックマークしたすべてのユーザーに対して、更新操作によって通知の設定が true にトリガーされる必要があります。頭に浮かぶ大きな欠点は、記事が頻繁にブックマークされている場合、多くの行に対して通知を true に設定するとコストがかかる可能性があることです。利点は、通知のチェックが次のように簡単であることです。
SELECT article FROM bookmarks WHERE user = 1234 AND notify = true;
最終的な考え
ページ ビューの数 (およびシステムが通知をチェックする回数) が記事の更新数を上回る場合、2 番目の方法の方がはるかに効率的であると思います。ただし、常にそうであるとは限りません。月に一度、数分間だけログインするブックマークされた記事がたくさんあるユーザーや、ほとんど毎分更新をチェックするユーザーがいるかもしれません。
記事が更新されると、システムがすべてのユーザーに通知を挿入する通知テーブルを含む 3 番目の方法もあります。ただし、通知を保存する必要があるため、方法#2の非効率的なバリアントだと思います。
両方のテーブルに数百万行が含まれている場合、どの方法が最も効率的ですか? より良いかもしれない別の方法はありますか?