[C#] DataTableをListに変換する時の速度を比較してみた


はじめに

DataTableへのアクセスは、比較的遅いという結果が出ています。

そして、Listの場合だと約5倍以上の速度が出るとも言われています。

DataTableに対するアクセス速度を比較する記事はいくつかありましたが、DataTableをList<T>に変換するまでの速度比較はなかなかなかったので、比較してみました。

今回の比較対象は下記の通りです。

  • DataTableを素直にループしてListに格納する
  • Linqを利用してListに変換する
  • リフレクションを利用してListに変換する

上記3つの変換方法に対して測定を実施してみます。

 

測定環境

  • Visual Studio 2019 Professional

 

測定時のデータ

  • カラム数:4カラム
  • レコード数:100万

 

ソース

今回は5回ループさせた結果を取得します。

 

(SamplePropertyクラス)

class SampleProperty
{
    public string Sample1 { get; set; }
    public string Sample2 { get; set; }
    public string Sample3 { get; set; }
    public string Sample4 { get; set; }
}

 

(Mainクラス)

static void Main(string[] args)
{
    int dataCount = 1000000;

    // DataTableを作成する
    var dt = new DataTable();
    dt.Columns.Add("Sample1");
    dt.Columns.Add("Sample2");
    dt.Columns.Add("Sample3");
    dt.Columns.Add("Sample4");

    for (var j = 0; j < dataCount; j++)
    {
        var dr = dt.NewRow();
        for (var i = 0; i < dt.Columns.Count; i++)
        {
            dr[dt.Columns[i].ColumnName] = Guid.NewGuid().ToString("N");
        }
        dt.Rows.Add(dr);
    }

    List<SampleProperty> spList = new List<SampleProperty>();
    var stopwatch = new Stopwatch();

    //ループを使った処理
    for(int loop = 0; loop < 5; loop++)
    {
        stopwatch.Start();
        for (int result = 0; result < dt.Rows.Count; result++)
        {
            SampleProperty sp = new SampleProperty();
            sp.Sample1 = dt.Rows[result]["Sample1"].ToString();
            sp.Sample2 = dt.Rows[result]["Sample2"].ToString();
            sp.Sample3 = dt.Rows[result]["Sample3"].ToString();
            sp.Sample4 = dt.Rows[result]["Sample4"].ToString();
            spList.Add(sp);
        }
        stopwatch.Stop();
        Console.WriteLine("計測時間(Loop): " + stopwatch.ElapsedMilliseconds + "ms");

        stopwatch.Reset();
        spList = new List<SampleProperty>();

        // Linqを使った処理
        stopwatch.Start();
        spList = (from DataRow dr in dt.Rows
                  select new SampleProperty()
                  {
                      Sample1 = dr["Sample1"].ToString(),
                      Sample2 = dr["Sample2"].ToString(),
                      Sample3 = dr["Sample3"].ToString(),
                      Sample4 = dr["Sample4"].ToString()
                  }).ToList();

        stopwatch.Stop();
        Console.WriteLine("計測時間(Linq): " + stopwatch.ElapsedMilliseconds + "ms");

        stopwatch.Reset();
        spList = new List<SampleProperty>();

        // Generic Methodを使った処理(Refrection)
        stopwatch.Start();
        spList = ConvertDataTable<SampleProperty>(dt);
        stopwatch.Stop();
        Console.WriteLine("計測時間(Refrection): " + stopwatch.ElapsedMilliseconds + "ms");

        stopwatch.Reset();
        spList = new List<SampleProperty>();
    }
}

private static List<T> ConvertDataTable<T>(DataTable dt)
{
    List<T> data = new List<T>();
    foreach (DataRow row in dt.Rows)
    {
        T item = GetItem<T>(row);
        data.Add(item);
    }
    return data;
}

private static T GetItem<T>(DataRow dr)
{
    Type temp = typeof(T);
    T obj = Activator.CreateInstance<T>();

    foreach (DataColumn column in dr.Table.Columns)
    {
        foreach (PropertyInfo pro in temp.GetProperties())
        {
            if (pro.Name == column.ColumnName)
                pro.SetValue(obj, dr[column.ColumnName], null);
            else
                continue;
        }
    }
    return obj;
}

 

結果

それぞれの測定結果は下記の通りとなりました。

対象 Loop Linq Refrection
1回目 1020ms 417ms 2127ms
2回目 973ms 407ms 2340ms
3回目 983ms 407ms 2061ms
4回目 988ms 400ms 2078ms
5回目 986ms 413ms 2084ms

 

上記をみてみると、Linqでの変換が一番早く、Refrectionを利用した場合はLinqを使用した場合の時と比べて5倍も時間がかかっているという結果が得られました。

変換方法によってはかなり差がでています。

 

最後に

少ないデータの場合だとどの変換方法を利用しても問題はありませんが、大規模データの場合は、かなりの差がでます。

参考になれば幸いです。