時間ベースの行フィルタの推奨事項
アプリケーションのユーザーは、テーブルに対して時間ベースのデータ サブセットを要求することがよくあります。たとえば、販売員が先週の注文データを必要としたり、イベント プランナが次週のイベントのデータを必要とする場合などです。多くの場合、アプリケーションでは、GETDATE() 関数を含むクエリを使用して、この処理を実行します。次の行フィルタ ステートメントについて考えてみましょう。
WHERE SalesPersonID = CONVERT(INT,HOST_NAME()) AND OrderDate >= (GETDATE()-6)
このタイプのフィルタを使用すると、マージ エージェントの実行時には、2 つの処理 (このフィルタに適合する行をサブスクライバにレプリケートする処理と、このフィルタに適合しない行をサブスクライバ側でクリーンアップする処理) が常に発生すると推測するのが普通です (HOST_NAME() を使用したフィルタ処理の詳細については、「パラメーター化された行フィルター」を参照してください)。ところがマージ レプリケーションでは、データに対して行フィルタをどのように定義したかに関係なく、前回の同期以降に変更されたデータのレプリケートおよびクリーンアップのみが行われます。
マージ レプリケーションで行を処理するには、行内のデータが行フィルタに適合していて、前回の同期以降にデータが変更されている必要があります。SalesOrderHeader テーブルでは、行が挿入されると OrderDate が入力されます。挿入はデータ変更なので、行は、期待どおりにサブスクライバにレプリケートされます。ただし、フィルタに適合しなくなった行 (7 日前以前の注文の行) がサブスクライバ側にある場合、他のなんらかの理由で更新されていない限り、その行はサブスクライバから削除されません。
イベント プランナの事例では、このようなフィルタ処理に伴う問題がさらに強く浮き彫りになります。Events テーブルに対する次のフィルタについて考えてみましょう。
WHERE EventCoordID = CONVERT(INT,HOST_NAME()) AND EventDate <= (GETDATE()+6)
イベントを格納しているテーブルでは、イベント当日のかなり前に挿入が行われることがあります。次週のイベントの挿入が 1 か月前に行われ、別の理由で行が更新されなかった場合、行フィルタに適合していても、行はサブスクライバにレプリケートされません。
また、パブリケーションの構成方法によって、マージ レプリケーションがフィルタを評価するタイミングはさまざまです。
パブリケーションが事前計算済みパーティションを使用している場合 (既定)、行の挿入時および更新時に、フィルタが評価されます。
パブリケーションが事前計算済みパーティションを使用していない場合、マージ エージェントの実行時に、フィルタが評価されます。
事前計算済みパーティションの詳細については、「事前計算済みパーティションによるパラメータ化されたフィルタのパフォーマンス最適化」を参照してください。フィルタが評価されるタイミングは、どのデータがフィルタに適合するかということに影響します。たとえば、パブリケーション側で事前計算済みパーティションが使用されており、2 日ごとにデータを同期する場合、販売員のデータのサブセットには、予期した日付よりも最高 2 日分古い行が含まれている可能性があります。
時間ベースの行フィルタを使用するための推奨事項
次に示す方法は、時間に基づいてフィルタ処理を行う際の強力でわかりやすいアプローチです。
テーブルに、データ型 bit の列を追加する。この列は、行をレプリケートするかどうかを示すために使用します。
時間ベースの列ではなく新しい列を参照する行フィルタを使用する。
スケジュールでマージ エージェントが実行される前に列を更新する SQL Server エージェント ジョブ (または別のメカニズムでスケジュールされたジョブ) を作成する。
この方法を使用すると、GETDATE() などの時間ベースの方法を使用した場合の欠点を補い、パーティションに対してフィルタが評価されるタイミングを決める問題を回避できます。Events テーブルの次の例を考えてみましょう。
EventID |
EventName |
EventCoordID |
EventDate |
Replicate |
---|---|---|---|---|
1 |
Reception |
112 |
2006-10-04 |
1 |
2 |
Dinner |
112 |
2006-10-10 |
0 |
3 |
Party |
112 |
2006-10-11 |
0 |
4 |
Wedding |
112 |
2006-10-12 |
0 |
このテーブルの行フィルタは、次のようになります。
WHERE EventCoordID = CONVERT(INT,HOST_NAME()) AND Replicate = 1
SQL Server エージェント ジョブは、各マージ エージェントを実行する前に、次のような Transact-SQL ステートメントを実行できます。
UPDATE Events SET Replicate = 0 WHERE Replicate = 1
GO
UPDATE Events SET Replicate = 1 WHERE EventDate <= GETDATE()+6
GO
1 行目では、Replicate 列を 0 に再設定しています。2 行目では、今後 7 日以内に発生するイベントの列を 1 に設定しています。この Transact-SQL ステートメントが 2006 年 10 月 7 日に実行されると、テーブルが次のように更新されます。
EventID |
EventName |
EventCoordID |
EventDate |
Replicate |
---|---|---|---|---|
1 |
Reception |
112 |
2006-10-04 |
0 |
2 |
Dinner |
112 |
2006-10-10 |
1 |
3 |
Party |
112 |
2006-10-11 |
1 |
4 |
Wedding |
112 |
2006-10-12 |
1 |
次週のイベントは、レプリケート準備済みとしてフラグが付けられています。イベント コーディネータ 112 が使用するサブスクリプションでマージ エージェントが次に実行されると、1 行目以外の行がサブスクライバにダウンロードされ、1 行目がサブスクライバから削除されます。