2

さて、私は PHP と MySQL を使用してフォーラム ソフトウェアを作成することを楽しんでいますが、常に私を悩ませていることが 1 つあります。

フォーラムのリストを表示するフォーラムのメイン ページ。各フォーラムには、フォーラム名、そのフォーラムで行われた投稿の数、そのフォーラムで行われたディスカッションの数、およびフォーラムの最後の投稿者が表示されます。これらすべてが異なるテーブルに格納されているときに、そのすべてのデータを取得するという問題があります。それを取得することは大した問題ではなく、実際にはまったく問題ではありませんが、それを効率的に行うことが私が求めていることです。

私の現在のアプローチはこれです。さまざまなテーブル (「投稿」、「ディスカッション」、「フォーラム」など) からデータを取得する代わりに、現在の投稿、ディスカッション、および最後の投稿者の数をフォーラム テーブル自体に静的に格納します。 「フォーラム」テーブルを更新し、投稿数を 1 増やし、最後の投稿者を更新します。新しいディスカッションを作成している場合は、ディスカッションも 1 増やします。これは、何らかの理由で非効率的で汚いように思えますが、それは私だけかもしれません。

そして、恐ろしく効率が悪いのではないかと私が恐れているもう 1 つのアプローチがあります。実際に「投稿」、「ディスカッション」、「フォーラム」の各テーブルに出向き、データを取得します。これの問題は、1 つのページに何百ものフォーラムが存在する可能性があることです...そして、投稿またはディスカッションの数を取得するために COUNT ステートメントを使用する必要があります。つまり、サブクエリを使用する必要があります。最後のポスターを取得するための 3 番目のサブクエリ。そうは言っても...クエリは、次の疑似コードのようなものになります。

SELECT foruminfo, (
    SELECT COUNT(id)
    FROM posts
    WHERE forumId = someid
), (
    SELECT COUNT(id)
    FROM discussions
    WHERE forumId = someid
), (
    SELECT postinfo
    FROM posts
    WHERE forumId = someid
    ORDER BY postdate
    DESC LIMIT 1
)
FROM forums
ORDER BY position DESC;

したがって、基本的に、何百ものフォーラムがリストされている場合、これらのサブクエリは何百回も実行できます。また、毎秒何百人ものユーザーがページを表示しているため、これはかなりの負担になるのではないでしょうか? サブクエリが通常のクエリと同じ量の負荷を引き起こすかどうかは完全にはわかりませんが、もしそうなら、それは確かに恐ろしく非効率的であるように思われます.

何か案は?:(

4

1 に答える 1

2

以前に大規模なフォーラム システムを構築したことがありますが、パフォーマンスを向上させるための鍵は、可能な限りすべてを非正規化することです。

JOIN本当に人気のあるページでは現実的に使えません。発行するクエリの数を最小限に抑える必要があります。サブセレクトは絶対に使用しないでください。インデックスが正確なユースケースをカバーしていることを常に確認してください。実行に 1 ~ 5 ミリ秒以上かかるクエリは、大規模に実行されているサイトで動作するには遅すぎる可能性があります。深刻な負荷が原因で、15 ミリ秒のクエリを実行するのに突然 10 倍の時間がかかる場合、最適化された 1 ミリ秒のクエリは許容できる 10 ミリ秒かかりますが、150 ミリ秒以上かかります。あなたはそれらが常に 0.00 であることを目指しており、これを行うことは可能です。

クエリを実行して応答を待っているときはいつでも、他に何もできないことを覚えておいてください。少し不注意になると、リクエストを処理するよりも速く受信し、システム全体が崩壊します。

つまり、ページのレイアウトや表示する情報を考慮し、スキーマを可能な限り正確に一致させることです。必要最低限​​のものまでそぎ落とします。不必要な妥協をせずに、最終出力にできるだけ近い形式で表現してください。

ユーザー名、アバター、投稿タイトル、投稿数、投稿日を表示している場合、それがデータベースにあるフィールドです。はい、別のユーザー データベースを使用することはできますが、可能な限りすべてを単純な構造に置き換えて、次のようにシンプルにします。

SELECT id, username, user_avatar, post_title, post_count, post_time FROM posts
  WHERE forum_id=?
  ORDER BY id DESC

通常、相手usersの名前を取得するには別のテーブルに参加する必要があり、特定のアバターを取得するには別のテーブルに参加し、投稿数を取得するにはディスカッション テーブルに参加する必要があります。ストレージ戦略を変更することで、これらすべてを回避できます。

私が働いていた場合、過去だけでなく将来にも投稿できることが要件だったので、あなたのposition. これが当てはまらない場合は、id次のように、順序付けに主キーを使用してください。

INDEX post_order (forum_id, id)

SUMorを使用するCOUNTことは完全に問題外です。カウンターキャッシュ列が必要です。これらは、特定のフォーラムにあるメッセージの数を保存するものです。はい、正規化されていないデータと同様に、同期がずれることがあります。そのため、必要に応じてデータを完全に再構築するために、ツールを追加してそれらをチェックする必要があります。通常、これは、発生した可能性のある小さな破損を修復するために 1 日 1 回実行される cron ジョブとして実行できます。ほとんどの場合、実装が正しく行われていれば、完全に同期されます。

他に注意すべき点は、可能であれば投稿をスレッドに分割することです。テーブルが小さいほど、高速になります。すべての投稿をふるいにかけて各スレッドのトップレベルの投稿を見つけるのは、特に一般的なシステムでは非常に時間がかかります。

また、オプションである場合は、 Memcachedなどで回避できるものはすべてキャッシュします。たとえば、ユーザーの友達リストは、友達が追加または削除されない限り変更されないため、データベースからそのリストを常に選択する必要はありません。最速のデータベース クエリは、作成したことがないものですよね?

これを適切に行うには、各ページのレイアウトとそこに書かれている情報を知る必要があります。あまり人気のないページはそれほど最適化する必要はありませんが、主要な火種はすべて慎重に検討する必要があります。多くの場合と同様に、トラフィックの 80% がコードベースの 20% にしか当たらないという 80/20 ルールが進行している可能性があります。それがあなたが最高の状態になりたいところです。

于 2013-05-01T04:07:29.140 に答える