SqlBulkCopyを使って高速に大量のテストデータを作成(それでも2時間以上かかっているがな(゚Д゚))

テスト用に1億件分のSQL Serverのデータが欲しくなったので、テストデータ作成プログラムを作ってみたり(・ω・)
普通にINSERTしていくと数百件/秒くらいの速度しか出ないので、SqlBulkCopyを使って高速に作成。
SqlBulkCopyを使うと処理速度は2桁違うわけですが、1億レコードともなるとそれでも2時間以上かかったりして(゚Д゚;)


ちなみにテストプログラムのソースはこんなんです。

static void Main(string[] args)
{
    Stopwatch watch = Stopwatch.StartNew();

    SqlBulkCopy sbc = new SqlBulkCopy(Settings.Default.ConnectionString,
                                      SqlBulkCopyOptions.TableLock);
    sbc.DestinationTableName = "Search";

    int effected = 0;
    for( int i = 0; i < 10000; i++ )
    {
        sbc.WriteToServer( new TestDataReader( i * 10000, 10000, words ) );
        effected += 10000;
        Debug.WriteLine( String.Format( "{0, 9} : {1} : {2} tps",
                         effected, watch.Elapsed,
                         (int)( effected / watch.Elapsed.TotalSeconds ) ) );
    }
}

10,000件のバルクインサートを10,000回実行しています。


テスト用のデータを作成するDataReaderはこんなカンジで。

class TestDataReader : IDataReader
{
    private readonly int max;
    
    private int current = 0;

    public TestDataReader(int start, int limit)
    {
        this.current = start;
        this.max = start + limit;
    }

    public int FieldCount
    {
        get { return 17; }  // 列の数固定
    }

    public bool Read()
    {
        return this.current++ < this.max;
    }

    public object GetValue(int i)
    {
        if ( i == 0 )
        {
            return this.current;
        }
...
    }

    public string GetName(int i) { throw new NotImplementedException(); }

... 後のメソッドはNotImplementedExceptionOK ...
}

GetValue()メソッドでは、列のインデックスによって返すデータを変えています。
テスト用のテーブルはこんな構造のものを使っているんですが。

CREATE TABLE [dbo].[Search](
    [Id] [int] NOT NULL,
    [Flag1] [char](1) NOT NULL,
    [Flag2] [char](1) NOT NULL,
    [Flag3] [char](1) NOT NULL,
    [Flag4] [char](1) NOT NULL,
    [Flag5] [char](1) NOT NULL,
    [Flag6] [char](1) NOT NULL,
    [Flag7] [char](1) NOT NULL,
    [Flag8] [char](1) NOT NULL,
    [Data1] [nvarchar](max) NOT NULL,
    [Data2] [nvarchar](max) NOT NULL,
    [Data3] [nvarchar](max) NOT NULL,
    [Data4] [nvarchar](max) NOT NULL,
    [Data5] [nvarchar](max) NOT NULL,
    [Data6] [nvarchar](max) NOT NULL,
    [Data7] [nvarchar](max) NOT NULL,
    [Data8] [nvarchar](max) NOT NULL,
    CONSTRAINT [PK_Search] PRIMARY KEY CLUSTERED ( [Id] ASC )
)

Id列には連番を、Flag*列にはRandomで"1"〜"5"までの値を設定。
Data*列には辞書ファイル(約30,000語)からランダムに文字を抽出して繋げて、適当な文章を設定。
品詞までは見ていないので、「大食ブラジャーさすが沿道付きまと嫌い昇天遭遇壇上払い戻し」みたいなおかしな文章ですが(・ω・)


データファイルは38GBくらいになっちゃったでにょろーん(´・ω・`)