負荷の下での挿入パフォーマンスの向上:なぜですか?


19

非常に非正規化されたテーブルへの挿入を実行するコードがあります。テーブルには、〜100〜300 +の範囲の列数があります。これは、Windows Server 2008上で実行されるSQL Server 2008 R2です。

各挿入は、同じトランザクションの下のいくつかのテーブルへの挿入で構成されます。一部の挿入はNHibernateによってバッチ処理されますが、一部は挿入できませんが、それらはすべて同じトランザクションの下にあります。

挿入を実行するコードを繰り返し呼び出して、たとえば500回挿入を実行すると、平均で約360ミリ秒になります。

奇妙なことに、4つのプロセス(Windows Server 2008の4つの異なるコマンドプロンプトから同じexeを実行)を使用してテストコードを同時に実行すると、呼び出しごとの挿入パフォーマンスが大幅に向上します。バーストは90ミリ秒(ほぼX4の高速)になります。コードから挿入時間を測定しています。

4つのプロセスは互いに何も知らないので、これはSQL Serverと関係があると考えていますが、その理由はまったくわかりません。なぜこれが起こっているのか、挿入がそれほど頻繁ではないときに同じパフォーマンスを得ることができる構成があるかどうかを知りたいです。

dbレベルで何が起こっているかを理解するためのSQL Server監視方法に関する提案も同様に歓迎します。

回答:


15

考えられる理由の1つは、4つの同時プロセスがログフラッシュのより好ましいパターンを生成することです。通常、各ログフラッシュは、単一の実行プロセスの場合よりも多くのデータを書き込みます。

トランザクションログのスループット/フラッシュサイズが要因かどうかを判断するには、以下を監視します。

内部制限に達していることを確認してください。SQL Server 2008 R2では、64ビットバージョンのデータベースごとに最大32の未処理(非同期)ログフラッシュI / Oが可能です(32ビットでは8のみ)。3840KBの未処理IOの合計サイズ制限もあります。

詳細情報および詳細情報:


12

@PaulWhiteが言うすべてに加えて...

外部キーが配置されている場合、すべての挿入では、参照される各テーブルでチェックを行う必要があります。360ミリ秒しか得られないので、あなたのように聞こえます。

とにかく、それらのテーブルをチェックすることは、データをディスクにロードするのではなく、RAMに既に持っていることで大いに助けられます。

RAMにデータをロードすることは実行の重要な部分であり、一度だけ実行する必要があるように思えます。

また、効果的なプランキャッシングであり、クエリを最初にコンパイルする必要があり、後続の呼び出しでそのフェーズを回避できることもあります。


ありがとうロブ。パフォーマンスの問題は、挿入中に使用されるテーブルの数が多いことに関連しています。外部キーはありません。パフォーマンス上の理由で削除しました。モデルとドメインの要件により、外部キーを使用できます。RAMにデータをロードしておらず、挿入は常に変化する着信要求によって動的に形成されます。私は基本的にOLTPのスター/スノーフレーク(ish)スキーマを誤用し、最高のパフォーマンスで逃げようとしています。
mahonya

2
@mahonya、明示的にデータをRAMにロードしていなくても、SQL Serverは挿入操作を実行する前に、まず必要なインデックスとデータページをバッファーキャッシュに読み込む必要があります。同時挿入スレッドは、1つのスレッドが読み取りオーバーヘッドを引き起こし、他のスレッドがキャッシュ内のデータにアクセスするように、キャッシュを暖める効果がある場合があります。
ダン・グスマン

@DanGuzmanに感謝します-そして、はい、mahonya、あなたのキャッシュがうまく暖められている可能性が高いです。待機をチェックして、物理的なI / Oがボトルネックの原因になっているかどうかを確認します。
ロブファーリー

@DanGuzman Agreedに感謝します。dbインデックスキャッシュの高速化は、おそらくPostgresでRobの入力を誤解していたのに慣れているものです。
mahonya

-3

一部のサーバー/ CPU / OSはパターンを記憶しています。キャッシュのような。

あなたは同じことを4回やっているので、私はそれがコーナーをカットする方法があると確信しています再利用されたコードを見て、キャッシュのように実行します(example2)または最初のプロセスが大きすぎてすべてに収まる可能性があります(ram example3)。

例1:0111110000110111110000111011111000011110111110000

例2:0111110000 | 11 | 0111110000 | 111 | 0111110000 | 1111 | 0111110000

example3:0111110000011111000001111100000111110000 example3:ループ:0111110000

私はubuntuサーバーがmysqlクエリを繰り返してこれを行うことを知っています。キャッシュに保存することができますが、実際には時間の差は10〜40mmだけですが、合計されます。私が学校にいたとき、プログラム(perl / php)がそのキャッシュを使用して高速化する必要があることを示すクラスがありました。

しかし、それはプログラム、それがどの言語であるか、何にコンパイルされているか、どのようにプログラムされたかに依存するかもしれません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.