SqlBulkCopy のベンチマーク

.NET 2.0 で、大量のデータをインポートするクラス SqlBulkCopy が導入された。その性能を試してみたのでメモ。

テスト結果

試行したPCの性能は以下のとおり。
CPU : Pen4 2.4GHz , RAM : 512MB , OS : WinXPSP2 , DB : SQLServer 2005 Express
各データ数に対して連続で5回試行し、その平均をとってみた。

データ数      SqlCommand      SqlBulkCopy
     100 :       108.6 [ms]       15.0 [ms]
    1000 :       990.2 [ms]       80.6 [ms]
   10000 :      7999.6 [ms]      193.4 [ms]
  100000 :     75634.0 [ms]     1696.4 [ms]

1000件くらいなら1件ずつINSERTでも我慢できないレベルじゃないけど、1万件を超えると迷わず SqlBulkCopy を使えという感じかな。残念なのは、クラス名が示すように SQLServer 用にしか用意されていないこと。

テストコード

前半は SqlCommand を使って Table1 に1件ずつ INSERT している。
後半では、Table1 からデータを DataTable に抽出して SqlBulkCopy で Table2 にインポートしている。

string constr = @"Data Source=.\sqlexpress;Initial Catalog=testdb;Integrated Security=True";
using (SqlConnection con = new SqlConnection(constr)) {
    con.Open();
    SqlCommand c = new SqlCommand("INSERT INTO Table1 VALUES(@id,@name)", con);
    c.Parameters.Add("@id", SqlDbType.Int);
    c.Parameters.Add("@name", SqlDbType.NVarChar);

    DateTime start = DateTime.Now;
    for (int i = 1; i <= COUNT; i++) {
        c.Parameters["@id"].Value = i;
        c.Parameters["@name"].Value = "name";
        c.ExecuteNonQuery();
    }
    TimeSpan span = DateTime.Now - start;

    Log(span, true);
}

DataTable table = new DataTable();

using (SqlConnection con = new SqlConnection(constr)) {
    con.Open();

    SqlCommand command = new SqlCommand("SELECT * FROM Table1", con);
    SqlDataAdapter adapter = new SqlDataAdapter(command);
    adapter.Fill(table);
}

using (SqlConnection con = new SqlConnection(constr)) {
    con.Open();
    using (SqlBulkCopy copy = new SqlBulkCopy(con)) {
        copy.DestinationTableName = "Table2";

        DateTime start = DateTime.Now;
        copy.WriteToServer(table);
        TimeSpan span = DateTime.Now - start;

        Log(span, false);
    }
}