10億行を処理してカウントするためのデータベース設計


10

リアルタイムのGPSデータを約5000 prのレートで受信します。分(4つのTCPサーバーから)。各サーバーは単一の接続を使用してデータを挿入し、挿入と挿入の間でデータをバッファーします。15分ほどごとに、サービスがこのデータをフェッチし、それをトリップに処理します。旅行が生成されたら、実際のGPSデータは通常、それほど重要ではありません。ユーザーが地図上でルートを確認したい場合のみです。

問題は、データベースが挿入されるデータの速度に追いつくのに苦労しているように見えることです。負荷が増加すると、挿入時間が急激に増加し(> 30秒)、その結果、より多くのデータをバッファリングできるようになり、その結果、挿入が大きくなり、挿入時間が長くなります。

現在のデザイン、パフォーマンスを改善するために必要ないくつかのアイデア、いくつかの質問への回答、および人々が持っている可能性のあるその他のヒントについて、いくつかコメントをいただければ幸いです。

現在のデザイン

現在、データは1週間を表すテーブルに分割されており、1年以上経過したデータはセカンダリデータベースにアーカイブされます。挿入と読み取りの両方に使用される編集可能なビューで全体が結合されます。

テーブルデザイン

  • Id(PK、uniqueidentifier)
  • DeviceId(FK、int)
  • PersonId(FK、int)
  • VehicleId(FK、int)
  • TokenId(FK、int)
  • UtcTime(PK、datetime2(3))
  • 緯度(float)
  • 経度(float)
  • 速度(smallint)
  • 見出し(smallint)
  • 衛星(tinyint)
  • IOData(varbinary(100))
  • IgnitionState(tinyint)
  • UserInput(tinyint)
  • CreateTimeUtc(datetime2(3))

指数

  • DeviceId_CreateTimeUtc_Desc
  • DeviceId_UtcTime_Desc(クラスター化)
  • PersonId_UtcTime_Desc
  • TokenId_UtcTime_Desc
  • VehicleId_UtcTime_Desc

現在、毎週、インデックスを含めて約10 GBを占めています。現在、メインデータベースには約300 GBのデータがあります。

メインデータベースのデータテーブルには、1つのファイルを持つ独自のファイルグループがありますが、メインデータベースの他のすべてのテーブルと同じディスク上にあります。セカンダリデータベースは別のディスクにありますが、同じマシン上にあります。

新しいテーブルパーティション(週)が使用されるときに、インデックスの再構築ジョブも毎週実行していると思います。縮小は行われません。

マシンは12 GBのメモリを搭載した8コアHPであり、メインデータベースを保持するディスクはRAID 10を実行しています。

アイデア

  • プライマリデータベースに保存されるデータの量を、たとえば最大1か月に制限します。少なくとも、データベースをバックアップ/復元用に管理しやすくなりますが、これによりパフォーマンスの向上が見込めますか?
  • 現在のデータのファイルグループに2つのファイルを作成し、それらを2つの異なる物理パーティションに配布する
  • 現在のデータを保持するマスタースレーブデータベースを作成して、挿入と読み取りが異なるデータベースで実行されるようにする
  • 現在のデータのファイルをSSDディスクに配置します(ミラーリングによりSSDディスクとのパフォーマンスに違いが生じますか?)

さらに情報が必要な場合はお知らせください。パフォーマンスに影響を与える恐ろしいほど多くの要因があり、おそらくそれを調整する多くの方法があります。


コメントは詳細な議論のためのものではありません。この会話はチャットに移動しました
ポールホワイト9

回答:


8

毎分5000挿入は、毎秒約83挿入です。1秒あたり400の物理行を挿入する5つのインデックス。ワークロードがメモリ内にある場合、これは最小のサーバーにさえ問題を提起しません。これが行ごとの挿入であったとしても、私が考えることができる最も非効率的な方法を使用しています。1秒あたり83の簡単なクエリは、CPUの観点からは興味がありません。

おそらく、あなたはディスクに縛られています。これは、待機統計またはを見て確認できSTATISTICS IOます。

クエリは多くの異なるページに触れるので、バッファプールにはそれらすべてのスペースがありません。これにより、ページの読み取りが頻繁に行われ、おそらくディスクの書き込みもランダムになります。

増え続けるキーのために、最後に物理的にのみ挿入するテーブルを想像してください。ワーキングセットは1ページ、つまり最後のページになります。これはシーケンシャルIOを生成し、レイジーライターまたはチェックポイントプロセスがテーブルの「終わり」をディスクに書き込みます。

ランダムに配置された挿入を含むテーブルを想像してください(典型的な例:GUIDキー)。ここでは、挿入ごとにランダムなページがタッチされるため、すべてのページがワーキングセットです。IOはランダムです。これは、ワーキングセットに関しては最悪のケースです。

あなたは真ん中です。あなたのインデックスは構造(SomeValue, SequentialDateTime)です。最初のコンポーネントは、2番目のコンポーネントによって提供される連続性を部分的にランダム化します。" SomeValue" にはかなりの数の可能な値があるため、インデックスにランダムに配置された挿入ポイントが多数あると思います。

あなたはデータが毎週10GBのテーブルに分割されると言います。ワーキングセットは10GBに制限されているため、これは良い出発点です(実行する可能性のある読み取りを無視して)。ただし、12 GBのサーバーメモリでは、関連するすべてのページがメモリ内にとどまることはほとんどありません。

毎週の「パーティション」のサイズを減らすか、サーバーのメモリを少し増やすことができる場合は、おそらく問題ありません。

週の初めの挿入は、終わりの挿入よりも速いと思います。特定のデータサイズでベンチマークを実行し、パフォーマンスタンクが表示されるまでサーバーのメモリを徐々に減らして、開発サーバーでこの理論をテストできます。

すべての読み取りと書き込みがメモリに収まる場合でも、ランダムなダーティページフラッシュIOが残っている可能性があります。それを取り除く唯一の方法は、インデックス内の同じ場所にある位置に書き込むことです。インデックスを変換して(さらに)順次キーを使用できるようにすることができれば、非常に役立ちます。

簡単な解決策として、クライアントとメインテーブルの間にバッファリングレイヤーを追加します。ステージングテーブルに15分の書き込みを蓄積し、定期的にフラッシュする可能性があります。これにより、負荷の急上昇がなくなり、より効率的な計画を使用して大きなテーブルに書き込みます。


1
@usr非常に包括的で十分に説明された回答をありがとう!サーバーメモリの増加について、実際にはどの程度の影響があるかはわかっていませんが、実際にそうする必要があるのは非常に説得力のある理由です。約10000のデバイスID。ステージングテーブルに関して、インデックスがないテーブルを提案し、その後X分ごとにメインテーブルに挿入するジョブを提案していますか?
ゾンダーガード、2014年

@usr Reg。クラスタ化インデックスをシーケンシャルに変換するための提案、auto-incを追加できます。ID列(整数)、およびシーケンシャルを維持することのみを目的として、クラスター化インデックスをこの列に変更しますか?これはテーブル間で一意ではありませんが、主キーである限り、問題はありません。
ゾンダーガード、2014年

1
ステージングテーブルが小さく、クエリがそれと共存できる場合は、インデックスを作成する必要はありません。しかし、できます。(あなたが言うように)1つの戦略は、ID列にCIを作成することです。これは、CIが大きく、他のインデックスが小さい場合に機能します。CIは書き込みであるため、シーケンシャルになっているため、問題への寄与ははるかに少なくなります。この戦略は、意味のあるサイズの違いがある場合に最も成功します。; 別のアイデアは、1日あたり1つのテーブルを持つことです。たぶん毎月マージします。
usr

わかりましたので、CIのID列の作成を調査しましたが、残念ながら、分割ビューでは不可能です(ID列は許可されておらず、デフォルト値はなく、すべての列を挿入に含める必要があります)。多分、分割されたビューはあまり選択されていないデザインでしたが、コンサルタントによって推奨されました
ゾンダーガード、2014年

2
真剣にしかし、同じ問題に直面している人にとっては、書き込みが多く、読み取りがわずかしかない場合は、最後に追加して、インデックス作成を遅らせたいと思います。一方、高速な読み取りが必要で、挿入にかかる時間を気にしない場合は、クラスター化インデックスが必要です。
-tiktak
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.