0

テーブル

記事のテーブルがあると仮定しましょう:

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の非効率的なバリアントだと思います。

両方のテーブルに数百万行が含まれている場合、どの方法が最も効率的ですか? より良いかもしれない別の方法はありますか?

4

3 に答える 3

1

私は確かに解決策 1 を選び、記事のインデックスが (article,last_update) にあることを確認します。

于 2013-05-12T11:50:33.570 に答える
0

物事をより面白くするための 3 番目の解決策があります。;-) 両方のソリューションの混合物です。システムがほとんど使用されない昼夜があると想定し、新しいブックマークをすべてマークするために昼夜を問わず実行します。

それだけで「新着記事更新!」という情報が遅れてしまいます。あなたが望んでいない日のために。しかし、記事の更新時に「はい」に設定され、その夜間の更新実行時に「いいえ」にリセットされる追加の列「今日更新」(列挙型「はい」、「いいえ」、またはtinyint)を保存します。

次に、すべてのブックマークの「変更あり」を「変更あり」(ナイトリー cron から) のマークで表示し、バージョン 1 からの選択で情報を追加しますが、今日変更された記事に限定します。

おそらくほとんどの記事は毎日更新されないので、それで勝てるはずです。

もちろん、私は測定回答を承認しますが、優れたベンチマークを作成するには多くの仮定が必要です。

于 2013-05-12T12:43:26.500 に答える