私は現在、比較的大量のデータ用のストレージスキーマの実装を担当しています。データは主に現在のdata point
値を決定するためにアクセスされますが、データのトレンド分析のために過去6か月の履歴を追跡する必要もあります。
最近の要件は、過去1時間のmin
/max
/sum
値を追跡するために追加されました。
注:理想的には、MongoDBオプションを検討したいのですが、最初にSQL-Serverオプションを使い果たしたことを示す必要があります。
データ
次の表は、プライマリデータソースを示しています(最も頻繁に照会されます)。テーブルには約500万行が含まれます。データの変更は主にUPDATE
ステートメントであり、最初のデータのロード後に非常にまれなINSERT
ステートメントが発生します。常に[all values for a given data point
]を選択するため、dataPointId
でデータをクラスター化することを選択しました。
// 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億に達することは問題外ではありません)。
The Question(s)(はい、私は複数を求めています...それらはすべて密接に関連しています)。
現在、SQL-Server 2008 R2 Standard Editionデータベースを使用しています。テーブルパーティションで必要なパフォーマンスレベルを取得できる場合(またはSQL-Serverで必要なパフォーマンスレベルに到達できない場合はMongoDB)は、Enterprise Editionにアップグレードする可能性があります。以下についてご意見をお聞かせください。
1)過去1時間のmin
、max
およびsum
を計算する必要があると仮定すると(now - 60 minutes
のように)。最近のデータを追跡するための最良のアプローチは何ですか?
最近のデータをデータサービスのメモリに保持します。計算された最小/最大/平均を各データUPDATEとともに書き出します。
各UPDATEステートメント中に、履歴テーブルから最近の履歴をクエリします(次の質問に影響しますか?)。クエリはデータポイント値の最新データにアクセスするので、最後の100万件のレコードのみをスキャンする必要がありますか?
最近の履歴をDataPointValue行自体に格納して、履歴テーブルの検索を回避しますか?おそらく区切り文字列として保存され、UPDATEプロシージャ内で処理されますか?
検討していない他のオプション?
2)DataPointValueHistory
の場合、データブルに対するクエリは常にdataPointId
と1つ以上のvalueId
によるものになります。照会されるデータは通常、最後の日、週、または月のものですが、場合によっては6か月全体のものになることもあります。
現在、dataPointId/valueId/timeStampまたはtimeStamp/dataPointId/valueIdでクラスタ化する方が理にかなっているかどうかを試すサンプルデータセットを生成しています。このサイズのテーブルを扱った経験があり、洞察を提供してくれる人がいれば、それを歓迎します。インデックスの断片化を回避するために、後者のオプションに頼っていますが、クエリのパフォーマンスは重要です。
クラスターDataPointValueHistory
by dataPointId-> valueId-> timeStamp
クラスタDataPointValueHistory
by timeStamp-> dataPointId-> valueId
3)最後に、上記のように、DataPointValueHistory
テーブルをパーティション分割することは理にかなっていると思います。履歴データを最適に分割する方法に関する提案があれば、大歓迎です。
最初にタイムスタンプでクラスター化した場合、データを週ごとにパーティション化する必要があると考えています(合計27パーティション)。最も古いパーティションは、27週後に消去されます。
最初にdataPointIdでクラスター化されている場合、データをIDの係数で分割する必要があると思いますか?
テーブルのパーティション分割の経験は非常に限られているため、専門知識をいただければ幸いです。
1つのテーブルに数十億行ある分析ソリューションの構築について調査しているときに、この分析が非常に役立つことがわかりました。