[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倍も時間がかかっているという結果が得られました。
変換方法によってはかなり差がでています。
最後に
少ないデータの場合だとどの変換方法を利用しても問題はありませんが、大規模データの場合は、かなりの差がでます。
参考になれば幸いです。
関連記事
[C#] ICompareインターフェースを使用して2つのListを比較する方法
はじめに Unitテスト時に2つのList<T>の比較をICompareイ ...
[C#] Listに格納されている日付から現在日時に一番近いでデータを比較し取得する方法
はじめに List<DateTIme>に日時のリストが格納されており、現在 ...
[C#] Rss情報読み込み時にエラーが発生する場合の対応
はじめに 前回のRSS情報読み込み処理で、読み込みエラー(XMLExceptio ...
CentOS にインストールした.NET Core でコンソールアプリケーションを動かす
はじめに .NET Core SDKをインストールしたCentOS上で、ASP. ...
[C#] RSS情報のpubDateなどの日付のフォーマットを変更する
RSSデータの日付フォーマットを変更する RSSデータのpubDateなどは、下 ...