私は現在、比較的大量のデータ用のストレージスキーマの実装を担当しています。データは主に現在のdata point
値を判断するためにアクセスされますが、データの傾向分析のために過去6か月の履歴を追跡する必要もあります。
最近の要件は、過去1時間のmin
/ max
/ sum
値を追跡するために追加されました。
注:理想的には、MongoDBオプションを検討したいと思いますが、最初にSQL-Serverオプションを使い果たしたことを示す必要があります。
データ
次の表は、プライマリデータソース(最も頻繁にクエリされる)を表しています。テーブルには約500万行が含まれます。データの変更は主に、初期データのロード後のUPDATE
非常に不定期のINSERT
ステートメントを伴うステートメントになります。dataPointId
あなたがいつも選択するので、私はデータをクラスタリングすることを選びましたall values for a given data point
。
// Simplified Table
CREATE TABLE [dbo].[DataPointValue](
[dataPointId] [int] NOT NULL,
[valueId] [int] NOT NULL,
[timestamp] [datetime] NOT NULL,
[minimum] [decimal](18, 0) NOT NULL,
[hourMinimum] [decimal](18, 0) NOT NULL,
[current] [decimal](18, 0) NOT NULL,
[currentTrend] [decimal](18, 0) NOT NULL,
[hourMaximum] [decimal](18, 0) NOT NULL,
[maximum] [decimal](18, 0) NOT NULL
CONSTRAINT [PK_MeterDataPointValue] PRIMARY KEY CLUSTERED ([dataPointId],[valueId])
)
2番目のテーブルは、約31億行と著しく大きくなっています(過去6か月のデータを表します)。6か月以上前のデータは削除されます。それ以外の場合は厳密にデータINSERT
ステートメント(最大200行/秒、720,000行/時間、1700万行/週)。
// Simplified Table
CREATE TABLE [dbo].[DataPointValueHistory](
[dataPointId] [int] NOT NULL,
[valueId] [int] NOT NULL,
[timestamp] [datetime] NOT NULL,
[value] [decimal](18, 0) NOT NULL,
[delta] [decimal](18, 0) NOT NULL
CONSTRAINT [PK_MeterDataPointHistory] PRIMARY KEY CLUSTERED ([dataPointId], [valueId], [timestamp])
)
予想されるのは、追跡されるデータポイント値の数が400行/秒に増えると、このテーブルのサイズが2倍になることです(したがって、約100億に達することは問題ではありません)。
質問(はい、私は複数質問しています...それらはすべて密接に関連しています)。
現在、SQL-Server 2008 R2 Standard Editionデータベースを使用しています。テーブルパーティションで目的のパフォーマンスレベルを取得できる場合(またはSQL-Serverで必要なパフォーマンスレベルに到達できない場合はMongoDB)、Enterprise Editionにアップグレードする場合を考えます。以下についてご意見をお寄せください。
1)私は計算する必要があることを考えるとmin
、max
およびsum
過去1時間(のようにnow - 60 minutes
)。最近のデータを追跡するための最良のアプローチは何ですか:
データサービスのメモリに最近のデータを保持します。更新された各データで計算された最小/最大/平均を書き出します。
各UPDATEステートメント中に、履歴テーブルから最近の履歴を照会します(次の質問に影響しますか?)。クエリは、データポイント値の最新データにアクセスするため、最後の100万レコード程度をスキャンするだけですか?
履歴テーブルの参照を回避するために、DataPointValue行自体に最近の履歴を保存しますか?おそらく区切られた文字列として保存され、UPDATE proc内で処理されますか?
私が検討していない他のオプション?
2)の場合DataPointValueHistory
、データベースに対するクエリは常にby dataPointId
および1つ以上valueId
です。クエリされるデータは、通常、最後の日、週、または月になりますが、場合によっては6か月全体になります。
現在、dataPointId / valueId / timeStampまたはtimeStamp / dataPointId / valueIdでクラスター化する方が適切かどうかを試すためのサンプルデータセットを生成しています。このサイズのテーブルを扱った経験があり、洞察を提供したいと思っている人がいれば幸いです。インデックスの断片化を回避するために後者のオプションに傾いていますが、クエリのパフォーマンスは重要です。
クラスタ
DataPointValueHistory
> valueId - - > timeStampにdataPointIdによってクラスタ
DataPointValueHistory
> dataPointId - - > valueIdタイムスタンプで
3)最後に、上で述べたように、DataPointValueHistory
テーブルを分割することは理にかなっていると思います。履歴データを最適に分割する方法に関する提案は大歓迎です。
最初にタイムスタンプでクラスター化された場合、データは週ごとにパーティション分割する必要があると考えています(合計27パーティション)。最も古いパーティションは、27週後に削除されます。
最初にdataPointIdによってクラスター化された場合、データはidのモジュラスによって分割されるべきだと考えていますか?
テーブルパーティション分割の経験は非常に限られているため、専門知識をいただければ幸いです。