[.NET]DataTableの行追加やデータ修正が異様に遅い時に疑うべき点
.NETですが、はまったので備忘録として残しておきます。
今回会社で、あるプログラムの動作が遅いとの報告を受け、調査しました。
そのプログラムはC#で書かれたものだったのですが、どうやらDataTableに数万件のデータを追加しているタイミングで、異様に時間がかかっている様子でした。約2万件で1〜2分です。
処理も特に変なことをやっているわけではなく、単純にDataTable.NewRowでDataRowを生成し、各フィールドにデータを入れて、最後にDataTable.Rows.Addで追加しているだけ。
むむむ・・・(´・ω・`)
となってしまいました。
結論としては、行追加の処理前にDataTable.Selectメソッドを使って絞り込みをかけているのが原因でした。
処理に意味のない極端な例ですがこんなイメージです。
public void Sample(DataTable dt)
{
DataRow[] rows = dt.Select("フィールド名 = '値1'"); //こいつが原因!
for (int i = 0; i <= 20000; i++)
{
DataRow dr = dt.NewRow();
dr["フィールド名"] = "値2";
dt.Rows.Add(dr); //ここが異様に遅い
}
}
どうやら、Selectメソッドを使用したタイミングで、変な気を利かせて勝手にDefaultViewにインデックスを生成している様子。
以降、確かに同条件でSelectメソッドを使った時は速くなるのですが、行追加やデータ修正の度にインデックスの再生成が走り、遅くなっているという罠でした。
うーん、これは余計なお世話^^;
ちなみにDefaultViewにSortやFilterをかけても同様の現象が起こります。
対応としては、DefaultViewとは別のDataViewを生成してそちらで絞り込みをかけるか、ループやLinqで対応するかだと思います。同条件で複数回絞り込むなら、インデックスが使える前者でしょうか。
DataTableの速度に関しては、こちらのサイトが参考になります。
DataTableからのデータ抽出方法の性能比較 - かずきのBlog@hatena
ただ、こちらではLinqが最速という解になっていますが、大量件数の場合はやはりインデックスを利用した方が速かったです。