私が知る限り、通常の挿入を最適化するのと非常によく似た方法で一括挿入を最適化できます。通常、単純な挿入のクエリプランはあまり有益ではないため、プランがないことを心配する必要はありません。挿入を最適化するいくつかの方法を説明しますが、それらのほとんどは、質問で指定した挿入には適用されない可能性があります。ただし、将来的に大量のデータをロードする必要がある場合に役立ちます。
1.クラスタリングキーの順序でデータを挿入する
SQL Serverは、クラスター化インデックスのあるテーブルにデータを挿入する前に、データをソートすることがよくあります。一部のテーブルやアプリケーションでは、フラットファイルのデータを並べ替え、SQL Serverにデータが次のORDER
引数で並べ替えられていることを通知することで、パフォーマンスを向上させることができますBULK INSERT
。
ORDER({column [ASC | DESC]} [、... n])
データファイル内のデータの並べ替え方法を指定します。インポートされるデータがテーブルのクラスター化インデックス(存在する場合)に従って並べ替えられている場合、一括インポートのパフォーマンスが向上します。
IDENTITY
クラスター化されたキーとして列を使用しているので、これについて心配する必要はありません。
2. TABLOCK
可能であれば使用する
1つのセッションのみがテーブルにデータを挿入することが保証されている場合は、のTABLOCK
引数を指定できますBULK INSERT
。これにより、ロックの競合が減少し、一部のシナリオではログが最小限になる可能性があります。ただし、すでにデータが含まれているクラスター化インデックスを含むテーブルに挿入しているため、この回答で後述するトレースフラグ610がないと、最小限のログが得られません。
それTABLOCK
が不可能な場合は、コードを変更できないため、すべての希望が失われるわけではありません。使用を検討してくださいsp_table_option
:
EXEC [sys].[sp_tableoption]
@TableNamePattern = N'dbo.BulkLoadTable' ,
@OptionName = 'table lock on bulk load' ,
@OptionValue = 'ON'
別のオプションは、トレースフラグ715を有効にすることです。
3.適切なバッチサイズを使用する
バッチサイズを変更することで、挿入を調整できる場合があります。
ROWS_PER_BATCH = rows_per_batch
データファイル内のデータのおおよその行数を示します。
デフォルトでは、データファイル内のすべてのデータは単一のトランザクションとしてサーバーに送信され、バッチ内の行数はクエリオプティマイザーにとって不明です。ROWS_PER_BATCH(値> 0)を指定すると、サーバーはこの値を使用して一括インポート操作を最適化します。ROWS_PER_BATCHに指定する値は、実際の行数とほぼ同じにする必要があります。パフォーマンスの考慮事項については、このトピックで後述する「解説」を参照してください。
これは記事の後半からの引用です:
単一のバッチでフラッシュされるページ数が内部しきい値を超えると、バッチのコミット時にフラッシュするページを特定するために、バッファープールのフルスキャンが発生する可能性があります。このフルスキャンは、一括インポートのパフォーマンスを低下させる可能性があります。大きなバッファープールが低速のI / Oサブシステムと組み合わされている場合、内部しきい値を超える可能性が高くなります。大規模なマシンでのバッファオーバーフローを回避するには、TABLOCKヒントを使用しない(バルク最適化を削除する)か、より小さいバッチサイズ(バルク最適化を保持する)を使用します。
コンピュータはさまざまであるため、データの負荷でさまざまなバッチサイズをテストして、最適な方法を見つけることをお勧めします。
個人的には、1つのバッチに695行すべてを挿入するだけです。ただし、大量のデータを挿入する場合は、バッチサイズを調整すると大きな違いが生じる可能性があります。
4. IDENTITY
カラムが必要であることを確認します
私はあなたのデータモデルや要件については何も知りませんがIDENTITY
、すべてのテーブルに列を追加するという罠にはまりません。Aaron Bertrandはこれについて、悪い習慣と呼ばれる、すべてのテーブルにIDENTITY列を配置する記事を公開しています。明確にするために、IDENTITY
このテーブルから列を削除する必要があるとは言っていません。ただし、IDENTITY
列が不要であると判断して削除すると、挿入のパフォーマンスが向上する可能性があります。
5.インデックスまたは制約を無効にする
既存のデータと比較して大量のデータをテーブルにロードする場合は、ロード前にインデックスまたは制約を無効にし、ロード後に有効にする方が速い場合があります。大量のデータの場合、通常、SQL Serverがデータをテーブルにロードするのではなく、一度にすべてのインデックスを作成する方が非効率的です。11500行のテーブルに695行を挿入したようですので、この手法はお勧めしません。
6. TF 610を検討する
トレースフラグ610を使用すると、いくつかの追加シナリオで最小限のログが可能になります。IDENTITY
クラスター化されたキーを持つテーブルの場合、復旧モデルがシンプルまたは一括ログである限り、新しいデータページのログは最小限になります。一部のシステムではパフォーマンスが低下する可能性があるため、この機能はデフォルトでは無効になっていると思います。このトレースフラグを有効にする前に、慎重にテストする必要があります。推奨されるMicrosoftのリファレンスは、データロードパフォーマンスガイドであるようです。
トレースフラグ610での最小限のログ記録のI / Oへの影響
最小限に記録されたバルクロードトランザクションをコミットする場合、コミットが完了する前に、ロードされたすべてのページをディスクにフラッシュする必要があります。以前のチェックポイント操作でキャッチされなかったフラッシュされたページは、大量のランダムI / Oを作成する可能性があります。これを完全にログに記録された操作と比較してください。これは、代わりにログ書き込みで順次I / Oを作成し、コミット時にロードされたページをディスクにフラッシュする必要がありません。
ロードシナリオがチェックポイントの境界を越えないbtreeでの小さな挿入操作であり、I / Oシステムが遅い場合、最小限のロギングを使用すると、実際には挿入速度が遅くなる可能性があります。
私の知る限り、これはトレースフラグ610とは何の関係もありませんが、最小限のロギング自体では関係ありません。ROWS_PER_BATCH
チューニングに関する以前の引用は、これと同じコンセプトに達していると思います。
結論として、を調整するためにできることはおそらく多くありませんBULK INSERT
。私はあなたがあなたの挿入物で観察した読み取りカウントについて心配していません。SQL Serverは、データを挿入するたびに読み取りを報告します。次の非常に単純な例を考えますINSERT
。
DROP TABLE IF EXISTS X_TABLE;
CREATE TABLE X_TABLE (
VAL VARCHAR(1000) NOT NULL
);
SET STATISTICS IO, TIME ON;
INSERT INTO X_TABLE WITH (TABLOCK)
SELECT REPLICATE('Z', 1000)
FROM dbo.GetNums(10000); -- generate 10000 rows
からの出力SET STATISTICS IO, TIME ON
:
テーブル 'X_TABLE'。スキャンカウント0、論理読み取り11428
私は11428の読み取りを報告していますが、それは実用的な情報ではありません。場合によっては、最小限のロギングでレポートされる読み取りの数を減らすことができますが、その違いを直接パフォーマンスの向上に変換することはできません。