質問

トレードオフについての質問です。

ソーシャルネットワークを想像してみてください。各ユーザーにはステータス メッセージがあり、いつでも変更できます。彼がそれを変更すると、すべての友人にウォール (Facebook など) を通じて通知が届きます。

これを機能させるには。Users(id, name)、FriendLists(userId, friendsUserId)、Notifications(?) の 3 つのテーブルがあります。

ここで、各ユーザーの友達リストに約 50 人の友達がいると仮定します。通知テーブルをどのように実装するかというジレンマに直面しています。


1番目のオプション

CREATE TABLE Notifications
(
toUserId bigint NOT NULL,
[identity] bigint IDENTITY(1,1) NOT NULL,
fromUserId bigint NOT NULL,
data varchar(256) NOT NULL,
CONSTRAINT [PK_Notifications] PRIMARY KEY CLUSTERED (toUserId, [identity])
)

通知を送信します。

-- Get all friends of @fromUserId.
WITH Friends AS
   (SELECT FriendLists.friendUserId
 FROM FriendLists
 WHERE userId = @fromUserId)
-- Send updates to all friends.
SELECT
 friendUserId as toUserId,
 @fromUserId as fromUserId,
 @data as data
INTO Notifications
FROM Friends

この場合、ステータス変更ごとに 50 個のレコードを作成します (友達が 50 人いると仮定します)。これは悪いです。ただし、良い点は、toUserId にクラスター化インデックスがあるため、特定のユーザーの通知を取得するのが非常に高速であることです。

2番目のオプション

CREATE TABLE Notifications
(
toUserId bigint NOT NULL,
[identity] bigint IDENTITY(1,1) NOT NULL,
fromUserId bigint NOT NULL,
data varchar(256) NOT NULL,
CONSTRAINT [PK_Notifications] PRIMARY KEY CLUSTERED ([identity])
)
CREATE NONCLUSTERED INDEX [IX_toUserId] ON Notifications (toUserId ASC)

通知を送信します。

-- Get all friends of @fromUserId.
WITH Friends AS
   (SELECT FriendLists.friendUserId
 FROM FriendLists
 WHERE userId = @fromUserId)
-- Send updates to all friends.
INSERT INTO Notifications(toUserId, fromUserId, data)
    VALUES(friendUserId, @fromUserId, @data)

ここでは、ステータス更新ごとに 1 つのレコードのみを挿入します。これはいい。悪い点は、レコードが toUserId によってクラスター化されていないため、通知の取得が遅くなることです。


通知の受信 どちらの方法でも同じです。

SELECT TOP(50) fromUserId, [identity], data
FROM Notifications
WHERE toUserId  = @toUserId

それで、これについてどう思いますか?

役に立ちましたか?

解決

まず、常に各「壁」は、それが更新されるよりも多くの何回も見られることになるので、書き込みと比較して圧倒的なことを行っている読み込みます。だから、あなたが改善するくそ速い読み込みます。

第二に、大きなソーシャルネットワーキングサイトのこれらの種類に固有の問題の一つは、データの分布であるとき、という意味(シャーディング、パーティショニングは、単一のデータベースでは、これまですべてのアカウント、すべての友達、すべての通知を格納することが可能になることはありません)新しい通知が壁の上に置かれ、友人はの他のサーバー上で通知する必要があります。これは、更新がとにかくベースの非同期メッセージングです意味します。

だから私は間違いなく、読書用に最適化された構造となるだろう。

私はあなたがhttp://www.sdsqlug.org/presentations/May2009/MySpace_DB_Overviewのhref = "<のように、FacebookやMySpaceのようなサイトのアーキテクチャに関わる様々な人々によって行われ、公開プレゼンテーションの上に行くお勧めします。 PPTX」のrel = "nofollowをnoreferrer">このクリスタStelzmullerの1 の。彼らは彼らのデザインになり思考や推論の多くを説明します。

他のヒント

アップデートはのSELECT ...数桁に比べて非常に遅いです。プラス、あなたのサイトとしてあなたは、メモリ内のすべてのあなたのフェッチをキャッシュすることがありますので、選択の速度は些細なことだろうスケーリングします。

この状況では、クラスター化インデックスは実際には昇順で挿入される必要があるため、(toUser,identity) にクラスター化インデックスを作成するのは悪い考えのように思えます。もちろん、SQL はテーブルのソートを維持しますが、これには高いパフォーマンス コストがかかります (これが質問の要点です)。ただし、一般に、特定の順序ではないことが事前にわかっている挿入は、次のような場合には推奨されません。クラスター化インデックス。ここはとても良いです 三つ 一部 記事 クラスター化インデックスの推奨事項について。

そうは言っても、私はクラスター化インデックスとして ID 列を使い続け、toUserId とおそらく datetime 列に非クラスター化インデックスを作成します。datetime 列を含めることで、最近のデータをより効率的にクエリできます。

遅い更新に関しては、ソーシャル ネットワーキング サイトでのステータス更新は、メッセージ キューにとって最適な状況です。そうすることで、必要に応じてデータベースを調整して読み取りを高速化することができ、書き込みパフォーマンスに影響を与える場合でも、ユーザーが苦しむ必要がなくなります。彼らの観点からすると、「定着」するまでに少し時間がかかるとしても、更新は瞬時に行われました。

非常に大規模なデータベースの場合は、パーティショニング戦略 (新しいデータにはより小さく管理しやすいテーブル、古いデータにはより大きな/大量のインデックスが付けられたテーブル) とレプリケーション ソリューションについて説明できる SQL の達人に従うことにします。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top