web-dev-qa-db-ja.com

リストからのSqlBulkCopy <>

単純なオブジェクトのList <>からSqlBulkCopyで大きな挿入を行うにはどうすればよいですか?

カスタムIDataReaderを実装しますか?

28

オブジェクトのリストから単純に DataTableを作成 し、SqlBulkCopy.WriteToServerを呼び出して、データテーブルを渡します。

次のものが役立つ場合があります。

SqlBulkCopyで最大のパフォーマンスを得るには、適切な BatchSize を設定する必要があります。 10,000はうまく機能するようですが、データのプロファイルを作成してください。

SqlBulkCopyOptions.TableLock を使用すると、より良い結果が得られる場合もあります。

SqlBulkCopyパフォーマンスの興味深く有益な分析が見つかります here

20
Winston Smith

FastMember を使用すると、DataTable(私のテストではパフォーマンスが2倍以上)を経由することなくこれを実行できます。

using(var bcp = new SqlBulkCopy(connection))
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description"))
{
    bcp.DestinationTableName = "SomeTable";
    bcp.WriteToServer(reader);
}

ObjectReaderは一般的でないソースでも機能することに注意してください。また、事前にメンバー名を指定する必要はありません(ただし、ColumnMappingsアスペクトのSqlBulkCopyObjectReader自体で指定しない場合)。

52
Marc Gravell

パーティーには遅刻しますが、MicrosoftからこのEntityDataReaderクラスを追加する場合、これを行うAsDataReader()拡張メソッドがあります。 https://github.com/matthewschrager/リポジトリ/blob/master/Repository.EntityFramework/EntityDataReader.cs

(例[List].AsDataReader()実装:)

var connStr = "";
using (var connection = new SqlConnection(connStr)) 
{
    var startTime = DateTime.Now;
    connection.Open();
    var transaction = connection.BeginTransaction();
    try
    {
        //var connStr = connection.ConnectionString;
        using (var sbCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
        {
            sbCopy.BulkCopyTimeout = 0;
            sbCopy.BatchSize = 10000;
            sbCopy.DestinationTableName = "Foobars";
            var reader = Foobars.AsDataReader();
            sbCopy.WriteToServer(reader);
        }
        transaction.Commit();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        transaction.Rollback();
    }
    finally
    {
        transaction.Dispose();
        connection.Close();
        var endTime = DateTime.Now;
        Console.WriteLine("Upload time elapsed: {0} seconds", (endTime - startTime).TotalSeconds);
    }
}
9
RJB

最初にSqlBulkCopyを呼び出して何を達成しようとしているのかによっては、テーブル値パラメーター(TVP)を使用する方が理にかなっている場合があります。 TVPを使用すると、カスタムタイプのコレクションを送信するのが簡単になります。データをストリームインできるため、DataTableを回避でき(@Marc Gravellの回答と同様)、SqlBulkCopyも回避できます。 TVPは、ストアドプロシージャを呼び出してTVPデータを渡し、INSERT(これは、 SqlBulkCopyの場合)。また、新しく作成されたSqlDataReader値などのIDENTITYデータを介してデータを取得することもできます。この回答に例といくつかの追加メモを追加しました: 可能な限り最短時間で1000万レコードを挿入するにはどうすればよいですか? 。そして数年前、私はSQL Server Central(無料の登録が必要です) アプリケーションからSQL Server 2008へのデータのストリーミング に関する記事を書きました。これは、リンクされた回答にも記載されており、 300万行のテキストファイルからストリーミングされたカスタムタイプのジェネリックリスト。

1
Solomon Rutzky