1

次のスキーマを持つテーブルがあります。

CREATE TABLE Measurement (
  HubId bigint NOT NULL
  ,DeviceId bigint NOT NULL
  ,Timestamp datetime NOT NULL
  ,Value bigint NOT NULL
)

1秒間に約100,000レコードでこのテーブルにレコードをインポートし、複数の同時接続に分割します。テーブルをヒープ(つまり、インデックスなし)として扱い、を使用することで、このレベルのパフォーマンスを実現できますSqlBulkCopy。毎秒、100,000のユニークなHubId組み合わせDeviceIdTimestamp増分の組み合わせがあります。Value時間の経過とともに累積されます。

また、最新の2つの値(この場合は最後と最後から2番目-挿入は常に順番になります)をGROUP BY HubId, DeviceId1秒に1回読み取る必要がありますが、生成する行のサブセット(ユーザーが関心のある行)に対してのみです。最後の2つの値のリアルタイムの差。

さらに、履歴の目的で、15分ごとに1回データを15分のスライスに集約する必要があります。このデータは、前の15分のスライスの最大値と現在の15分のスライスの最大値に基づいて集計されます...これはデータセット全体で発生する必要がありますが、一意HubIdDeviceId組み合わせのために複数の接続に分割できます。累積的であるためValue、これは事実上、前および現在の15分のスライスの最後の値です。

インデックスを使用してテーブルに一括挿入すると、排他テーブルロックにエスカレーションされます。さらに、排他的なテーブルロックにエスカレートせずにクエリを実行させることはできないようです。

誰かがこれを構築するための最良の方法について私にいくつかの指針を与えることができますか?最善の方法を模索している壁に頭をぶつけています...

ありがとう、ディーン

4

1 に答える 1

0

そのため、何度も行ったり来たりした後、必要なスループットを達成するために、アプローチを多少変更しました。結局のところ、私たちはそこにいる瞬間に100,000レコード/秒しか気にせず、それらは集約されたリアルタイムの値の継続的にローリングするセットを更新するために使用されます。

多数のワーカースレッドを使用して100,000行を一時ヒープテーブルに一括挿入し(したがって、4つのワーカースレッドを使用して、それぞれが約25,000行を処理します)、クラスター化インデックスを一時テーブルに適用します。次に、一時テーブルのデータをリアルタイムテーブルと集計テーブルに直接マージし、一時テーブルを削除します。ここでは、ROWLOCKヒントを使用して、SQLがTABLOCKやPAGLOCKではなくROWLOCKを取得するように強制します。これにより、ワーカースレッド間で必要以上の競合が発生します。

さらに、メモリ内のデータ構造を、キューではなく不可逆スタックに変更しました。私たちの場合、これは通常、最新のデータのみを考慮し、古いデータを削除しても問題がないため、適切です。

ポケットのエースとしてパーティショニングを使用しますが、現在はSQL Server Standard Editionに制限されているため、現在、開発マシンの外部に展開することはできません。

乾杯、ディーン

于 2012-09-07T15:28:16.160 に答える