21

私の Web サイトには、フォロワー/フォロー システム (Twitter のようなもの) があります。私のジレンマは、誰が誰をフォローしているかを処理するデータベース構造を作成することです。

私が思いついたのは、次のようなテーブルを作成することでした:

 id  |  user_id  |  followers |  following
  1  |    20     |  23,58,84  |  11,156,27
  2  |    21     |  72,35,14  |  6,98,44,12
 ... |   ...     |    ...     |     ...

基本的に、各ユーザーには、フォロワーとフォローしているユーザーの列を含む行があると考えていました。フォロワーとフォローしているユーザーのユーザー ID はコンマで区切られます。

これはそれを処理する効果的な方法ですか?そうでない場合、最良の代替手段は何ですか?

4

4 に答える 4

54

それはそれを行う最悪の方法です。ノーマライゼーションに反対です。2 つの独立したテーブルがあります。ユーザーと User_Followers。ユーザーはユーザー情報を保存します。User_Followers は次のようになります。

id | user_id | follower_id
1  | 20      | 45
2  | 20      | 53
3  | 32      | 20

User_Id と Follower_Id は、Users テーブルの Id 列を参照する外部キーになります。

于 2013-11-01T19:43:05.997 に答える
17

これまでのところ、他の回答で提案されているよりも優れた物理構造があります。

CREATE TABLE follower (
    user_id INT, -- References user.
    follower_id INT,  -- References user.
    PRIMARY KEY (user_id, follower_id),
    UNIQUE INDEX (follower_id, user_id)
);

InnoDB テーブルはクラスター化されているため、セカンダリ インデックスはヒープベースのテーブルとは異なる動作をし、それを認識していないと予期しないオーバーヘッドが発生する可能性があります。サロゲート プライマリ キーを使用するとid、正当な理由もなく1別のインデックスが追加され、{user_id, follower_id} および {follower_id, user_id} のインデックスが必要以上に太くなります (クラスター化されたテーブルのセカンダリ インデックスには暗黙的に PK のコピーが含まれるため)。 )。

上記のテーブルには代理キー idがなく、(InnoDB を想定して) 2 つの B ツリー (1 つはプライマリ/クラスタリング キー用、もう 1 つはセカンダリ インデックス用) によって物理的に表されます。これは、双方向の検索とほぼ同じくらい効率的です2 . 1 つの方向だけが必要な場合は、セカンダリ インデックスを破棄して、1 つの B ツリーだけに下げることができます。

ところで、あなたがしたことは原子性の原則、したがって1NFの違反でした。


1また、インデックスを追加するたびにスペースが必要になり、キャッシュの有効性が低下し、INSERT/UPDATE/DELETE のパフォーマンスに影響します。

2フォロワーからフォロワーへ、またはその逆。

于 2013-11-02T05:03:02.350 に答える
3

いいえ、あなたが説明するアプローチにはいくつかの問題があります。

まず、複数のデータ ポイントをカンマ区切りの文字列として保存すると、多くの問題が発生します。結合するのは難しく (これを使用して結合するlikeことはできますが、パフォーマンスが低下します)、検索が困難で遅く、希望する方法でインデックスを作成することもできません。

次に、フォロワーのリストとフォローしている人のリストの両方を保存すると、データが冗長になり (A が B をフォローしているという事実が 2 つの場所に表示されます)、これはスペースの無駄であり、可能性も生み出します。データの非同期化 (データベースが B のフォロワー リストに A を表示し、A のフォロー リストに B を表示しない場合、データは一貫性がなく、回復が非常に困難です)。

代わりに、結合テーブルを使用してください。これは、各行にユーザー ID とフォロワー ID が含まれる個別のテーブルです。これにより、物事を 1 か所に格納したり、インデックス付けと結合を行ったり、その行に追加の列を追加したりできます。たとえば、次の関係がいつ開始されたかを表示できます。

于 2013-11-01T19:46:34.323 に答える