4

私はアプリケーションを設計していますが、その 1 つの側面は、大量のデータを SQL データベースに受け取ることができることです。次のような bigint ID を持つ単一のテーブルとしてデータベース構造を設計しました。

CREATE TABLE MainTable
(
   _id bigint IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    field1, field2, ...
)

私が持っている質問とは関係がないので、どのようにクエリを実行するつもりなのかは省略します。

SqlBulkCopy を使用してこのテーブルにデータを挿入するプロトタイプを作成しました。研究室ではうまく機能しているように見えました。毎秒約 3K レコードの速度で数千万のレコードを挿入できました (完全なレコード自体はかなり大きく、約 4K です)。このテーブルの唯一のインデックスは自動インクリメント bigint であるため、大量の行がプッシュされた後でも速度が低下することはありませんでした。

ラボの SQL サーバーが比較的脆弱な構成の仮想マシン (4Gb RAM、他の VM ディスク sybsystem と共有) であることを考慮すると、物理マシンのスループットが大幅に向上することを期待していましたが、そうはなりませんでした。パフォーマンスの向上はごくわずかでした。物理マシンでの挿入が 25% 高速になる可能性があります。3 ドライブの RAID0 を構成した後でも、1 つのドライブよりも 3 倍高速でした (ベンチマーク ソフトウェアで測定) が、改善は見られませんでした。基本的に、より高速なドライブ サブシステム、専用の物理 CPU、および 2 倍の RAM は、パフォーマンスの向上にはほとんどつながりませんでした。

次に、Azure で最大のインスタンス (8 コア、16Gb) を使用してテストを繰り返しましたが、同じ結果が得られました。そのため、コアを追加しても挿入速度は変わりませんでした。

現時点では、次のソフトウェア パラメーターをいじってみましたが、パフォーマンスが大幅に向上することはありませんでした。

  • SqlBulkInsert.BatchSize パラメータの変更
  • 複数のスレッドから同時に挿入し、スレッド数を調整する
  • SqlBulkInsert でテーブル ロック オプションを使用する
  • 共有メモリ ドライバを使用してローカル プロセスから挿入することにより、ネットワーク レイテンシを排除する

私はパフォーマンスを少なくとも 2 ~ 3 倍向上させようとしています。当初の考えでは、より多くのハードウェアを投入するとうまくいくというものでしたが、今のところそうではありません。

だから、誰かが私を推薦できますか:

  • ここで、どのリソースがボトルネックであると疑われる可能性がありますか? 確認方法は?
  • 単一の SQL サーバー システムがあることを考慮して、確実にスケーラブルな一括挿入の改善を試みる方法はありますか?

更新load app は問題ではないと確信しています。別のスレッドの一時キューにレコードを作成するため、挿入があると次のようになります (簡略化):

===>start logging time
int batchCount = (queue.Count - 1) / targetBatchSize + 1;
Enumerable.Range(0, batchCount).AsParallel().
    WithDegreeOfParallelism(MAX_DEGREE_OF_PARALLELISM).ForAll(i =>
{
    var batch = queue.Skip(i * targetBatchSize).Take(targetBatchSize);
    var data = MYRECORDTYPE.MakeDataTable(batch);
    var bcp = GetBulkCopy();
    bcp.WriteToServer(data);
});
====> end loging time

タイミングがログに記録され、キューを作成する部分が重要なチャンクを取得することはありません

UPDATE2そのサイクルの各操作にかかる時間を収集することを実装しました。レイアウトは次のとおりです。

  • queue.Skip().Take()- 無視できる
  • MakeDataTable(batch)- 10%
  • GetBulkCopy()- 無視できる
  • WriteToServer(data)- 90%

UPDATE3 SQL の標準バージョン用に設計しているため、エンタープライズ バージョンでのみ利用可能なパーティション分割に依存できません。しかし、私はパーティション分割スキームの変種を試しました:

  • 16 個のファイル グループ (G0 から G15) を作成し、
  • 挿入専用の 16 個のテーブル (T0 から T15) を作成し、それぞれが個別のグループにバインドされました。テーブルにはインデックスがまったくなく、クラスター化された int ID さえありません。
  • データを挿入するスレッドは、それぞれ 16 個のテーブルすべてを循環します。これにより、各一括挿入操作が独自のテーブルを使用することがほぼ保証されます

これにより、一括挿入で最大 20% の改善が得られました。CPU コア、LAN インターフェイス、ドライブ I/O は最大化されておらず、最大容量の約 25% で使用されていました。

UPDATE4今は最高の状態になっていると思います。次の手法を使用して、挿入を適切な速度でプッシュすることができました。

  • 各一括挿入は独自のテーブルに入り、結果はメインのテーブルにマージされます
  • テーブルは一括挿入ごとに新しく再作成され、テーブル ロックが使用されます
  • DataTable の代わりにhereのIDataReader 実装を使用しました。
  • 複数のクライアントからの一括挿入
  • 各クライアントは、個々のギガビット VLAN を使用して SQL にアクセスしています
  • メイン テーブルにアクセスするサイド プロセスは NOLOCK オプションを使用します
  • sys.dm_os_wait_stats と sys.dm_os_latch_stats を調べて競合を排除しました

この時点で、回答された質問のクレジットを誰に与えるかを決めるのに苦労しています。「回答」が得られなかった皆さん、申し訳ありません。本当に苦渋の決断でした。皆さんに感謝します。

UPDATE5 : 次の項目は、いくつかの最適化を使用できます。

  • DataTable の代わりにhereのIDataReader 実装を使用しました。

CPUコア数が多いマシンでプログラムを実行しない限り、リファクタリングが必要になる可能性があります。リフレクションを使用して get/set メソッドを生成しているため、CPU に大きな負荷がかかります。パフォーマンスが重要な場合は、リフレクションを使用する代わりに IDataReader を手動でコーディングしてコンパイルすると、パフォーマンスが大幅に向上します。

4

3 に答える 3

4

バルク ロード用に SQL Server をチューニングする際の推奨事項については、MSの『Data Loading and Performance Guide』とオンライン ブックからのバルク インポートを最適化するためのガイドラインを参照してください。SQL Server からの一括読み込みに焦点を当てていますが、ほとんどのアドバイスはクライアント API を使用した一括読み込みに適用されます。この文書は SQL 2008 に適用されます。どの SQL Server のバージョンを対象としているかは言及されていません。
両方とも、詳細に検討する価値のある非常に多くの情報を持っています。ただし、いくつかのハイライト:

  • 最小限の一括操作をログに記録します。一括ログまたは単純な復旧を使用します。トレースフラグ 610 を有効にする必要がある場合があります (ただし、これを行う際の注意事項を参照してください)。
  • バッチサイズを調整する
  • ターゲット テーブルの分割を検討する
  • 一括読み込み中にインデックスを削除することを検討してください

Data Loading and Performance Guideのこのフローチャートにうまくまとめられています。 ここに画像の説明を入力

他の人が言ったように、実験では IO が制限ではない可能性があることが示唆されているため、ボトルネックの原因を特定するには、いくつかのパフォーマンス カウンターを取得する必要があります。 Data Loading and Performance Guideには、監視する SQL 待機タイプとパフォーマンス カウンターのリストが含まれています (リンク先のドキュメントにはアンカーはありませんが、これはドキュメント全体の約 75% の「バルク ロードの最適化」セクションにあります)。

アップデート

リンクを見つけるのに少し時間がかかりましたが、 Thomas Kejser によるこの SQLBits トークも一見の価値があります。すべてを見る時間がない場合は、スライドを利用できます。ここにリンクされている資料の一部を繰り返しますが、特定のパフォーマンス カウンターの発生率が高い場合の対処方法について、他のいくつかの提案もカバーしています。

于 2012-06-23T06:43:30.020 に答える
2

多くのことを行ったようですが、Alberto Ferrari SqlBulkCopy パフォーマンス分析レポートを読む機会があったかどうかはわかりません。このレポートには、SqlBulkCopy に関連するパフォーマンスを考慮するためのいくつかの要因が記載されています。その論文で議論されている多くのことは、まだ試してみる価値があると思います。最初に試してみるとよいでしょう。

于 2012-06-23T01:39:34.607 に答える
1

CPU、IO、またはメモリの使用率が 100% にならない理由がわかりません。ただし、単に一括読み込み速度を向上させたい場合は、次のことを考慮してください。

  1. データ ファイルを異なるファイルに分割します。または、それらが異なるソースからのものである場合は、単純に異なるデータ ファイルを作成します。
  2. 次に、複数の一括挿入を同時に実行します。

状況によっては、上記が実行できない場合があります。できれば、読み込み速度が向上するはずです。

于 2012-06-29T17:16:16.097 に答える