10

パフォーマンスを向上させるために、DB 設計で高レベルの冗長な非正規化データを使用します。通常は結合または計算する必要があるデータを保存することがよくあります。たとえば、UserテーブルとTaskテーブルがある場合、すべてのTaskレコードにUsernameUserDisplayNameを重複して格納します。この別の例は、UserテーブルにTaskCountを格納するなど、集計を格納することです。

  • ユーザー
    • ユーザーID
    • ユーザー名
    • ユーザー表示名
    • タスク数
  • 仕事
    • タスク ID
    • タスク名
    • ユーザーID
    • ユーザー名
    • ユーザー表示名

アプリには挿入、更新、または削除操作よりも多くの読み取りがあり、ユーザー名などの一部の値はめったに変更されないため、これはパフォーマンスに優れています。ただし、大きな欠点は、アプリケーション コードまたはトリガーを介して整合性を強制する必要があることです。これは、更新の際に非常に面倒になる可能性があります。

私の質問は、SQL Server 2005/2010 でこれを自動的に行うことができるかということです...おそらく永続的/永続的なビューを介して。別の可能性のあるソリューションまたはテクノロジーを推奨する人はいますか? CouchDB や MongoDB などのドキュメント ベースの DB は、非正規化されたデータをより効果的に処理できると聞いています。

4

1 に答える 1

11

NoSQL ソリューションに移行する前に、まずインデックス付きビューを試すことをお勧めします。

http://msdn.microsoft.com/en-us/library/ms187864.aspx

と:

http://msdn.microsoft.com/en-us/library/ms191432.aspx

インデックス付きビューを使用すると、ベース データを適切に正規化されたテーブルに保持し、データの整合性を維持しながら、そのデータの非正規化された「ビュー」を提供できます。トランザクションの多いテーブルにはこれをお勧めしませんが、書き込みよりも読み取りの方が重いとおっしゃっていたので、これが機能するかどうかを確認することをお勧めします。

2 つの例のテーブルに基づいて、1 つのオプションは次のとおりです。

1) 次のように定義された User テーブルに列を追加します。

TaskCount INT NOT NULL DEFAULT (0)

2) 次のように定義されたタスク テーブルにトリガーを追加します。

CREATE TRIGGER UpdateUserTaskCount
ON dbo.Task
AFTER INSERT, DELETE
AS

;WITH added AS
(
    SELECT  ins.UserID, COUNT(*) AS [NumTasks]
    FROM    INSERTED ins
    GROUP BY    ins.UserID
)
UPDATE  usr
SET     usr.TaskCount = (usr.TaskCount + added.NumTasks)
FROM    dbo.[User] usr
INNER JOIN  added
        ON  added.UserID = usr.UserID


;WITH removed AS
(
    SELECT  del.UserID, COUNT(*) AS [NumTasks]
    FROM    DELETED del
    GROUP BY    del.UserID
)
UPDATE  usr
SET     usr.TaskCount = (usr.TaskCount - removed.NumTasks)
FROM    dbo.[User] usr
INNER JOIN  removed
        ON  removed.UserID = usr.UserID
GO

3) 次に、次のビューを実行します。

SELECT   u.UserID,
         u.Username,
         u.UserDisplayName,
         u.TaskCount,
         t.TaskID,
         t.TaskName
FROM     User u
INNER JOIN   Task t
        ON   t.UserID = u.UserID

次に、上記のリンクの推奨事項 (WITH SCHEMABINDING、Unique Clustered Index など) に従って、「永続化」します。上記のように SELECT のサブクエリで集計を行うのは非効率的ですが、この特定のケースは、書き込みよりも読み取りが多い状況で非正規化することを目的としています。したがって、インデックス付きビューを実行すると、集計を含む構造全体が物理的に保存されるため、読み取りごとに再計算されません。

現在、一部のユーザーがタスクを持っていない場合に LEFT JOIN が必要な場合、それらの作成に関する 5000 の制限により、インデックス付きビューは機能しません。その場合、非正規化された構造である実際のテーブル (UserTask) を作成し、ユーザー テーブルのみのトリガーを介して入力することができます (上で示したトリガーを実行すると仮定します。 Task テーブル)、または User テーブルの TaskCount フィールドをスキップして、両方のテーブルに Triggers を設定して、UserTask テーブルに入力することができます。結局、これは基本的に、同期トリガーを記述する必要なく、インデックス付きビューが行うことです。

于 2011-01-25T02:08:05.097 に答える