前回:[.NET][C#]当然っちゃ当然だけどDataTableとか使いようによっては遅い
前回の続きです。
前回は、DataTableからのデータの読み取りの性能ばっかり見てましたが、書き込み時も、ちょっと気を抜くと、性能劣化が起きたりします。
BeginEdit, EndEdit
DataRowの複数カラムの値を更新する際に、更新前と更新後をBeginEditとEndEditメソッドで囲むことで、性能が桁違いになったりします。
百聞は一見にしかずなので、実際にテスト用プログラムを組んで実行してみました。
using System;
using System.Data;
using System.Diagnostics;
namespace DataRowAccess
{
class Program
{
// 列数
private const int COLUMN_COUNT = 30;
// 行数
private const int ROW_COUNT = 50000;
static void Main(string[] args)
{
var dt = MakeDataTable();
NoBeginEditAndEndEdit(dt);
dt.AcceptChanges(); // 一旦変更を反映
BeginEditAndEndEdit(dt);
}
// テスト用データテーブルを作成する
private static DataTable MakeDataTable()
{
var dt = new DataTable();
// カラム作成
for (int i = 0; i < COLUMN_COUNT; i++)
{
dt.Columns.Add("COL_" + i, typeof(string));
}
// 行データ追加
for (int i = 0; i < ROW_COUNT; i++)
{
var row = dt.NewRow();
foreach (DataColumn col in dt.Columns)
{
row[col] = col.ColumnName + "_" + i;
}
dt.Rows.Add(row);
}
return dt;
}
// BeginEditとEndEdit無し
private static void NoBeginEditAndEndEdit(DataTable dt)
{
var watch = new Stopwatch();
watch.Start();
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
{
row[col] = "XXXX";
}
}
watch.Stop();
Console.WriteLine("BeginEdit,EndEdit無し: " + watch.ElapsedMilliseconds + "ms");
}
// BeginEditとEndEdit有り
private static void BeginEditAndEndEdit(DataTable dt)
{
var watch = new Stopwatch();
watch.Start();
foreach (DataRow row in dt.Rows)
{
row.BeginEdit();
foreach (DataColumn col in dt.Columns)
{
row[col] = "OOOO";
}
row.EndEdit();
}
watch.Stop();
Console.WriteLine("BeginEdit,EndEdit有り: " + watch.ElapsedMilliseconds + "ms");
}
}
}
DataTableにダミーデータを詰め込んで、BeginEdit,EndEditの有無で、データの書き込み速度を比較しています。
実行してみると・・・
ぜんぜん違います。
ここまで極端に性能差が出ることは、あまりないかもしれませんが、複数列の値をどかっと書き換える処理なんかでは、有効活用しましょう。