DataSetの行/列ルックアップの速度?
-
02-07-2019 - |
質問
最近、DataSetに保存されたデータを使用して、非常に重い処理を行う必要がありました。コードのボトルネックを特定するのに役立つツールを使用することになりました。ボトルネックを分析しているとき、DataSetのルックアップはそれほど遅くありませんでした(ボトルネックではありませんでした)が、予想よりも遅いことに気付きました。 DataSetsは、ルックアップO(1)を実行する何らかのHashTableスタイルの実装を使用すると常に仮定していました(または、少なくともHashTablesと思うもの)。ルックアップの速度は、これよりも大幅に遅いようです。
.NETのDataSetクラスの実装について何かを知っている人が、知っていることを共有してくれないかと思っていました。
次のような場合:
DataTable dt = new DataTable();
if(dt.Columns.Contains("SomeColumn"))
{
object o = dt.Rows[0]["SomeColumn"];
}
Contains(...)
メソッドの検索時間、および Object o
に格納する値の取得時間はどれくらいですか?私はそれがHashTableのように非常に高速だと思っていたでしょう(HashTablesについて理解していることが正しいと仮定します)が、それはそうではないようです...
メモリからそのコードを書いたので、「構文的に正しい」ものがないかもしれません。
解決
Via Reflector DataRow [" ColumnName"]の手順は次のとおりです。
- ColumnNameからDataColumnを取得します。行のDataColumnCollection [" ColumnName"]を使用します。内部的に、DataColumnCollectionはそのデータ列をHastableに格納します。 O(1)
- DataRowの行インデックスを取得します。インデックスは内部メンバーに保存されます。 O(1)
-
DataColumn [index]を使用して、インデックスでDataColumnの値を取得します。 DataColumnは、そのデータをSystem.Data.Common.DataStorage(内部、抽象)メンバーに保存します。
return dataColumnInstance._storage.Get(recordIndex);
具体的な実装例は、System.Data.Common.StringStorage(内部、封印済み)です。 StringStorage(およびチェックした他の具象DataStorage)は、値を配列に保存します。 Get(recordIndex)は、単にrecordIndexの値配列のオブジェクトを取得します。 O(1)
全体としてO(1)になりますが、それは操作中のハッシュと関数呼び出しにコストがかからないという意味ではありません。 DataRowsまたはDataColumnsの数が増えてもコストがかからないことを意味します。
DataStorageが値に配列を使用することに関心があること。行を追加または削除すると、簡単に再構築できるとは想像できません。
他のヒント
実際には、列を参照するときに整数を使用することをお勧めします。これにより、パフォーマンスの面で大幅に改善できます。物事を管理しやすくするために、定数整数を宣言できます。だからあなたがやったことの代わりに、あなたは行うことができます
const int SomeTable_SomeColumn = 0;
DataTable dt = new DataTable();
if(dt.Columns.Contains(SomeTable_SomeColumn))
{
object o = dt.Rows[0][SomeTable_SomeColumn];
}
ルックアップはO(n)になると想像します。どのタイプのハッシュテーブルも使用するとは思わないが、実際には行と列を見つけるためにより多くの配列を使用します。
実際、列名はハッシュテーブルに保存されていると思います。 O(1)または大文字と小文字を区別するルックアップの定数ルックアップである必要があります。それぞれに目を通す必要がある場合、もちろんO(n)になります。