19

Facebook と同様に、アプリケーションのユーザー間の関係を保存したいとします。

つまり、AがBの友人 (または何らかの関係) である場合、BAの友人です。この関係を保存するために、現在、次のように関係のテーブルに保存することを計画しています

  UID      FriendID
 ------    --------
 user1      user2
 user1      user3
 user2      user1

ただし、ここで 2 つのオプションに直面しています。

  1. user1 -> user2と の両方を格納する典型的なケースuser2->user1です。これにはより多くのスペースが必要になりますが、(少なくとも私の頭の中では) 特定のユーザーの友達を表示するために行を 1 回渡すだけで済みます。
  2. もう 1 つのオプションは、user1->user2ORuser2->user1のいずれかを格納することです。 のすべての友達を見つけたいときはいつでもuser1、テーブルの両方の列をクエリして、ユーザーの友達を見つけます。半分のスペースが必要ですが、(少なくとも私の頭の中では) 2 倍の時間がかかります。

まず、私の推論は適切ですか?はいの場合、私が忘れているボトルネックはありますか (スケーリング/スループットなどに関して)?

基本的に、ここにリストされているもの以外に、2 つの間にトレードオフはありますか。また、業界ではどちらが優先されますか?

4

3 に答える 3

23

これら 2 つのアプローチがデータベースで物理的にどのように表現されるかを次に示します。

ここに画像の説明を入力

両方のアプローチを分析しましょう...

アプローチ 1 (両方向がテーブルに格納されている):

  • PRO: よりシンプルなクエリ。
  • CON:一方向のみの挿入/更新/削除によってデータが破損する可能性があります。
  • MINOR PRO: 友情を複製できないようにするための追加の制約は必要ありません。
  • さらなる分析が必要です:
    1. TIE: 1 つのインデックスで両方向がカバーされるため、セカンダリ インデックスは必要ありません。
    2. TIE: ストレージ要件。
    3. TIE: パフォーマンス。

アプローチ 2 (テーブルに格納されている方向は 1 つだけ):

  • CON: より複雑なクエリ。
  • PRO: 反対方向がないため、反対方向の処理を忘れてデータが破損することはありません。
  • MINOR CON: が必要CHECK(UID < FriendID)なので、同じ友情が 2 つの異なる方法で表されることは決してなく、キーオン(UID, FriendID)がその仕事を行うことができます。
  • さらなる分析が必要です:
    1. TIE:クエリの両方向をカバー{UID, FriendID}するには、2 つのインデックスが必要です ( の複合インデックスと の複合インデックス{FriendID, UID})。
    2. TIE: ストレージ要件。
    3. TIE: パフォーマンス。

ポイント1は特に興味深いものです。MySQL/InnoDBは常にデータを クラスター化し、クラスター化されたテーブルではセカンダリ インデックスのコストが高くなる可能性があるため (この記事の「クラスタリングの欠点」を参照)、アプローチ 2 のセカンダリ インデックスが少ない行数の利点をすべて食い尽くしてしまうように見えるかもしれません。 . でも、セカンダリ インデックスにはプライマリとまったく同じフィールドが含まれているため (逆の順序でのみ)、この特定のケースではストレージのオーバーヘッドはありません。また、(テーブル ヒープがないため) テーブル ヒープへのポインターも存在しないため、通常のヒープ ベースのインデックスよりもストレージの面でさらに安価です。また、クエリがインデックスでカバーされていると仮定すると、クラスター化されたテーブルのセカンダリ インデックスに通常関連付けられているダブル ルックアップも発生しません。したがって、これは基本的に引き分けです (アプローチ 1 もアプローチ 2 も大きな利点はありません)。

ポイント 2はポイント 1 に関連しています。N 値の B ツリーを使用するか、それぞれが N/2 値を持つ 2 つの B ツリーを使用するかは問題ではありません。したがって、これも引き分けです。どちらのアプローチも、ほぼ同じ量のストレージを消費します。

同じ理由がポイント 3にも当てはまります。1 つの大きな B ツリーを検索しても、2 つの小さな B ツリーを検索しても、大きな違いはないため、これも引き分けです。

したがって、堅牢性のために、やや醜いクエリと追加の必要性にもかかわらずCHECK、アプローチ2を使用します.

于 2012-05-30T11:46:41.550 に答える
5

最近はストレージが比較的安いので気になりません。

私が心配するのは、情報を2回保存しているので、クリーンアップする必要があるということです。したがって、誰かを「友達から外す」場合は、1つだけでなく、2つのレコードを削除する必要があります。

その他の考慮事項は、検索とインデックス作成です。一貫した規則に従っている場合は、2つのユーザーIDの組み合わせをハッシュして存在を確認することには利点があります(ハッシュする前に常に高いIDを低いIDに追加するなど)。

だから今、あなたは他の可能性を持っています。2人のユーザー間の関係を照会することに興味がありますか?それとも、1人のユーザーの属性を調べることがより重要ですか?

これらは、システムが何をするかについての懸念です。DDD(ドメイン駆動設計)やCQRS(コマンドクエリ責任分離)などのテーマを見て、各領域が可能な限り簡単な方法で実装されるようにアプリを分割する方法を確認してください。これにより、複雑さの問題に遭遇することなく、後で微調整および最適化する手段が提供されます。

于 2012-05-29T23:25:00.053 に答える