web-dev-qa-db-ja.com

SQL Server 2008への非常に高速な挿入の方法

デバイスのデータを直接sqlテーブルに記録するプロジェクトがあります。

私はSQLサーバーに書き込む前にコードでほとんど処理を行いません(ところで2008エクスプレス)

通常、sqlhelperクラスのExecuteNonQueryメソッドを使用して、SPが予期するストアドプロシージャ名とパラメーターのリストを渡します。

これは非常に便利ですが、これを行うにははるかに高速な方法が必要です。

ありがとう。

26

INSERTステートメントまたはストアドプロシージャを含むExecuteNonQueryを使用すると、Expressで1秒間に数千の挿入が行われます。 4000〜5000 /秒は簡単に達成できますが、これは事実です。

通常、個々の更新の速度が低下するのは、ログフラッシュの待機時間であり、それを考慮する必要があります。最も簡単な解決策は、単純にバッチコミットすることです。例えば。 1000回の挿入ごと、または1秒ごとにコミットします。これにより、ログページがいっぱいになり、トランザクション内のすべての挿入に対するログフラッシュ待機のコストが償却されます。

バッチコミットでは、おそらくディスクログの書き込みパフォーマンスのボトルネックになりますが、ハードウェアを変更する(ログのRAID 0ストライプになる)こと以外には何もできません。

If以前のボトルネックに(可能性が低いとして)ヒットした場合、バッチ処理ステートメントを調べることができます。複数の挿入を含む1つのT-SQLバッチを送信します。しかし、これはめったに報われません。

もちろん、書き込みのサイズを最小限に抑える必要があります。つまり、テーブルの幅を最小限必要な列に減らし、非クラスター化インデックスを排除し、不要な制約を排除する必要があります。可能であれば、クラスター化インデックスの代わりにヒープを使用します。これは、ヒープの挿入がクラスター化インデックスの挿入よりもはるかに高速であるためです。

高速挿入インターフェイス(つまり、SqlBulkCopy)を使用する必要はほとんどありません。バッチコミットで通常のINSERTSとExecuteNoQueryを使用すると、一括挿入を展開する必要よりもはるかに高速にドライブの順次書き込みスループットを使い果たします。高速のSAN接続されたマシンで一括挿入が必要であり、Expressについて言及しているので、おそらくそうではありません。一括挿入は、バッチコミットを提供します。一括挿入ではなく、バッチコミットが高速化します。

他のパフォーマンステストと同様に、ランダム性を排除し、データベースとログを事前に割り当てますを確認してください。 。

46
Remus Rusanu

一括挿入は最小限に記録されるため、最速になります。

.NETには SqlBulkCopy Class もあります

4
SQLMenace

テーブル変数を使用して多くのレコードを挿入する良い方法は次のとおりです...

...ただし、テーブル変数は「メモリ内」にあるため、一度に1000レコードに制限することをお勧めします

この例では、3つのフィールド(CustID、Firstname、Lastname)を持つテーブルに2つのレコードを挿入します

--first create an In-Memory table variable with same structure
--you could also use a temporary table, but it would be slower

declare @MyTblVar table (CustID int, FName nvarchar(50), LName nvarchar(50))

insert into @MyTblVar values (100,'Joe','Bloggs')

insert into @MyTblVar values (101,'Mary','Smith')

Insert into MyCustomerTable

Select * from @MyTblVar
2
user2696172

通常、これは BULK INSERT を使用して行われます。基本的に、ファイルを準備してからBULK INSERTステートメントを発行すると、SQL Serverは可能な限り高速な方法でファイルのすべてのデータをテーブルにコピーします。

いくつかの制限があります(たとえば、更新する既存の行がある場合、「更新または挿入」タイプの動作を実行する方法はありません)が、それらを回避できる場合は、何も見つけることができませんもっと早く。

2
Dean Harding

挿入が遅くなる可能性があるのは、同じテーブルでのインデックスと読み取りまたは更新(ロック)です。両方を避け、インデックスやその他のアクティビティのない個別の保持テーブルに個々のトランザクションを挿入することで、あなたのような状況をスピードアップできます。次に、保持テーブルをメインテーブルに少し頻繁にバッチ処理します。

2
Joel Coehoorn

.NETの場合は、 SqlBulkCopy を使用します

1
Mitch Wheat

SPが実行されるのと同じ速度でしか実行できません。テーブルが適切にインデックス付けされていることを確認してください。クラスタ化インデックスがある場合は、狭く、一意で、増加していることを確認してくださいキー:残りのインデックスと制約(存在する場合)に大きなオーバーヘッドがないことを確認します。

ADO.NETレイヤーのオーバーヘッドはそれほど多くないはずです(SQLCommandの上にある他の.NETライブラリを使用する必要はありません)。 ADO.NET Asyncメソッドを使用して、アプリケーションの単一スレッドをブロックせずにストアドプロシージャへの複数の呼び出しをキューに入れることができる場合があります(これにより、複数のマシンをデータベースに挿入するのと同様に、潜在的に他のものよりも多くのスループットを解放できます) )。

それ以外に、あなたは本当にあなたの要件についてもっと話す必要があります。

1
Cade Roux