10

大量のデータを SQL サーバーに挿入しようとしています。私の宛先テーブルには、「ハッシュ」と呼ばれる一意のインデックスがあります。

SqlDataAdapter の実装を SqlBulkCopy に置き換えたいと考えています。SqlDataAapter には「ContinueUpdateOnError」というプロパティがあり、true に設定すると、adapter.Update(table) は可能なすべての行を挿入し、エラー行に RowError プロパティのタグを付けます。

問題は、どの行が挿入され、どの行が挿入されなかったのか (一意のインデックスのため) を追跡しながら、SqlBulkCopy を使用してできるだけ早くデータを挿入するにはどうすればよいかということです。

追加情報は次のとおりです。

  1. このプロセスは反復的であり、多くの場合、繰り返すスケジュールが設定されています。

  2. ソース テーブルと宛先テーブルは巨大になる可能性があり、場合によっては数百万行になります。

  3. 最初にハッシュ値を確認することは可能ですが、行ごとに 2 つのトランザクションが必要です (最初に宛先テーブルからハッシュを選択し、次に挿入を実行します)。adapter.update(table) の場合、行ごとのハッシュ ヒットをチェックするよりも、RowError をチェックする方が速いと思います。

4

3 に答える 3

7

SqlBulkCopy のエラー処理機能は非常に限定されており、デフォルトでは制約のチェックさえ行いません。

しかし、その高速、本当に本当に高速です。

重複キーの問題を回避し、どの行が重複しているかをバッチで特定する場合。1 つのオプションは次のとおりです。

  • トランを開始
  • テーブルで tablockx を取得し、現在のすべての「ハッシュ」値を選択して、HashSet に入れます。
  • 重複を除外して報告します。
  • データを挿入する
  • トランザクションをコミット

このプロセスは、大きなセットを挿入していて、テーブル内の初期データのサイズがそれほど大きくない場合に効果的に機能します。

問題の残りのコンテキストを含めるように質問を拡張してください。

編集

ここでいくつかのコンテキストが得られたので、別の方法でそれを実行できます。

  • 一時テーブルに一括挿入します。
  • シリアライズ可能なトランを開始
  • 宛先テーブルに既にあるすべての一時行を選択します...それらについて報告します
  • 一時テーブルのデータを実際のテーブルに挿入し、ハッシュで左結合を実行し、すべての新しい行を含めます。
  • トランザクションをコミットする

そのプロセスは往復で非常に軽く、スペックを考慮すると非常に高速になるはずです。

于 2009-06-17T01:05:04.163 に答える
4

すでに提案されているものとは少し異なるアプローチ。スローされたSqlExceptionを実行しSqlBulkCopyてキャッチします。

    Violation of PRIMARY KEY constraint 'PK_MyPK'. Cannot insert duplicate 
key in object 'dbo.MyTable'. **The duplicate key value is (17)**.

次に、複製された最初のレコードである ID 17 から、ソースからすべてのアイテムを削除できます。ここでは、私の状況に当てはまり、おそらくあなたの状況には当てはまらない仮定を立てています。つまり、重複は、アップロード中の SQL/ネットワーク エラーが原因で以前に失敗したものとまったく同じデータによって引き起こされたものです。SqlBulkCopy

于 2014-06-10T16:08:56.197 に答える
1

注:これは、サムの回答の要約であり、もう少し詳細があります

答えてくれたサムに感謝します。コメントのスペースの制約から、回答に入れました。

あなたの答えから導き出すと、2つの可能なアプローチがあります。

解決策1:

  • トランを開始
  • 「destinationtableでハッシュを選択」を実行して、ヒットする可能性のあるすべての「ハッシュ」値を取得します。ここで、ハッシュは(val1、val2、...)
  • 重複を除外して報告する
  • データを挿入
  • トランをコミット

解決策2:

  • 宛先テーブルのスキーマをミラーリングする一時テーブルを作成します
  • 一時テーブルへの一括挿入
  • シリアル化可能なトランザクションを開始します
  • 重複する行を取得します:「tempTableからハッシュを選択します。ここでtempTable.hash =destinationTable.hash」
  • 重複する行に関するレポート
  • 一時テーブルのデータを宛先テーブルに挿入します: "select * into destinationTable from temptable left join temptable.hash = destinationTable.hash where destinationTable.hash is null"
  • トランをコミットする

2つのアプローチがあるので、どちらのアプローチが最も最適化されているかということになります。どちらのアプローチも重複する行を取得してレポートする必要がありますが、2番目のアプローチでは追加の手順が必要です。

  • 一時テーブルの作成と削除
  • データを一時テーブルから宛先テーブルに移動するためのもう1つのSQLコマンド
  • ハッシュ衝突の割合に応じて、ネットワークを介して多くの不要なデータも転送します

これらが唯一の解決策である場合、最初のアプローチが勝つように思われます。皆さんはどう思いますか?ありがとう!

于 2009-06-18T01:08:11.743 に答える