次の構造のSQLデータテーブルがあります。
CREATE TABLE Data(
Id uniqueidentifier NOT NULL,
Date datetime NOT NULL,
Value decimal(20, 10) NULL,
RV timestamp NOT NULL,
CONSTRAINT PK_Data PRIMARY KEY CLUSTERED (Id, Date)
)
個別のIDの数は3000から50000の範囲です
。テーブルのサイズは10 億行を超えます。
1つのIDで、テーブルの5%までの数行をカバーできます。
このテーブルで最も実行されるクエリは次のとおりです。
SELECT Id, Date, Value, RV
FROM Data
WHERE Id = @Id
AND Date Between @StartDate AND @StopDate
更新を含め、Idのサブセットでデータの増分検索を実装する必要があります。
次に、呼び出し元が特定の行バージョンを提供し、データのブロックを取得し、返されたデータの最大行バージョン値を後続の呼び出しに使用する要求スキームを使用しました。
私はこの手順を書きました:
CREATE TYPE guid_list_tbltype AS TABLE (Id uniqueidentifier not null primary key)
CREATE PROCEDURE GetData
@Ids guid_list_tbltype READONLY,
@Cursor rowversion,
@MaxRows int
AS
BEGIN
SELECT A.*
FROM (
SELECT
Data.Id,
Date,
Value,
RV,
ROW_NUMBER() OVER (ORDER BY RV) AS RN
FROM Data
inner join (SELECT Id FROM @Ids) Ids ON Ids.Id = Data.Id
WHERE RV > @Cursor
) A
WHERE RN <= @MaxRows
END
どこ@MaxRows
チャンククライアントが自分のデータをお勧めします方法に応じて500,000 2,000,000の間の範囲であろう。
私はさまざまなアプローチを試しました:
- (Id、RV)のインデックス作成:
CREATE NONCLUSTERED INDEX IDX_IDRV ON Data(Id, RV) INCLUDE(Date, Value);
インデックスを使用して、クエリが行求めるRV = @Cursor
それぞれのId
中に@Ids
、その後、ソート結果をマージして、次の行を読んで、。
次に、効率は@Cursor
価値の相対的な位置に依存します。
データの終わりに近い場合(RV順)、クエリは瞬時に実行され、そうでない場合、クエリは最大で数分かかる場合があります(最後まで実行しないでください)。
このアプローチの問題は@Cursor
、データの終わり近くにあり、並べ替えが苦痛でない(クエリが返す行数が未満の場合でも必要ない@MaxRows
)か、さらに遅れており、クエリが@MaxRows * LEN(@Ids)
行を並べ替える必要があることです。
- RVのインデックス作成:
CREATE NONCLUSTERED INDEX IDX_RV ON Data(RV) INCLUDE(Id, Date, Value);
クエリはインデックスを使用して行を探し、そこでRV = @Cursor
すべての行を読み取り、要求されていないIDを破棄します@MaxRows
。
効率は、要求されたIDの%(LEN(@Ids) / COUNT(DISTINCT Id)
)とその分布に依存します。
要求されたId%が多いほど、破棄される行が少なくなり、読み取りがより効率的になり、要求されたId%が少ないほど、破棄される行が多くなり、同じ量の結果の行に対する読み取りが多くなります。
このアプローチの問題は、リクエストされたIDに含まれる要素が数個しかない場合、インデックス全体を読み取って目的の行を取得する必要がある可能性があることです。
- フィルターされたインデックスまたはインデックス付きビューの使用
CREATE NONCLUSTERED INDEX IDX_RVClient1 ON Data(Id, RV) INCLUDE(Date, Value)
WHERE Id IN (/* list of Ids for specific client*/);
または
CREATE VIEW vDataClient1 WITH SCHEMABINDING
AS
SELECT
Id,
Date,
Value,
RV
FROM dbo.Data
WHERE Id IN (/* list of Ids for specific client*/)
CREATE UNIQUE CLUSTERED INDEX IDX_IDRV ON vDataClient1(Id, Rv);
この方法では、完全に効率的なインデックス作成とクエリ実行プランが可能になりますが、デメリットがあります。1.実際には、動的SQLを実装してインデックスまたはビューを作成し、要求するプロシージャを変更して適切なインデックスまたはビューを使用する必要があります。2.ストレージを含め、既存のクライアントで1つのインデックスまたはビューを維持する必要があります。3.クライアントがリクエストされたIDのリストを変更する必要があるたびに、インデックスまたはビューを削除して再作成する必要があります。
自分のニーズに合った方法が見つからないようです。
増分データ検索を実装するためのより良いアイデアを探しています。これらのアイデアは、要求しているスキーマまたはデータベーススキーマを作り直すことを意味する可能性があります。
Value
列のみを変更します。@crokusek:RVではなくIDで並べ替えるのではなく、RVの代わりに並べ替えのワークロードを増やすだけで、メリットはありません。コメントの理由はわかりません。私が読んだことから、RVは、その列にデータを具体的に挿入しない限り一意である必要がありますが、アプリケーションはそうではありません。