2016-03-29 2 views
0

シリアル番号のリストがあり、これらの番号とIDに対応するデータテーブルから行を抽出する必要があります。私は同じのためにLINQクエリの下に使用しています:行を取得するためにlinq操作を最適化する方法

//list of serial numbers 
var serialNumAlreadyExisted = [1,2,3]; 
var varID = 2; 

//get the corresponding rows for these serial numbers 
var duplicateRows = (from row in dt.AsEnumerable() 
    where row.Field<int>("ID") == varID && 
    serialNumAlreadyExisted.Any(sr => sr == row.Field<string>("SERIAL_NUMBER")) 
    select row).ToList(); 

上記のコードは1-2K行に適していますが、50Kシリアル番号とDataTableの50Kレコードがある場合には多くの時間を要します。

これを最適化して処理時間を短縮する手段はありますか?

+0

'serialNumAlreadyExisted.Contains(row.Field (" SERIAL_NUMBER "))'はどうですか? –

+1

あなたは2つに参加することができます。それはおそらく私がやることですが、パフォーマンスの向上はメモリ内のセットで目立つものになるとは思っていません。実際には、メモリ内のすべてのものとの違いに気付いていることに私は非常に驚いています。 'DataTable'が熱心に読み込まれていることを覚えていませんか?最近は怠惰なバージョンがありますか?私は間違いなく、データの読み込みに時間がかかったと思っていますが、それは除外されていると思いますか? –

+0

'DataTable.Select'メソッドを試してみてください。例えば(パフォーマンスをテストするハードコーディングされた例): 'DataRow [] dupes = dt.Select(String.Format(" Id = 2 AND SERIAL_NUMBER IN( '1'、 '2'、 '3') "));' – ASh

答えて

2

私はあなたがあなたのシリアル番号がintまたはstringのリストであることを意図したかどうかわからないんだけど、あなたは文字通り持っているもの取って、それはおそらく、パフォーマンスが向上します同様に、stringにワンタイム変換を行うためにそう:

var serialStringsAlreadyExisted = serialNumAlreadyExisted.Select(x => x.ToString()).ToList(); 

次に、あなたはContainsまたはよりも効率的であるべきで、参加を進めることができます:

var duplicateRows = (
    from row in dt.AsEnumerable() 
    where row.Field<int>("ID") == varID 
    join serial in serialStringsAlreadyExisted on row.Field<string>("SERIAL_NUMBER") equals serial 
    select row) 
    .ToList(); 

編集

ちょうど速いスピードテストを行いました。 joinを使用すると、元のコードと100万行の比較で約半分の時間で完了します。

serialNumAlreadyExistedの項目数を20に増やした場合、joinを使用すると、ベースライン方法の時間の20%に近づきます。

1

O(1)にアクセスするHashSetContainsコールの組み合わせをお勧めします。この場合はAnyがコレクションを通過します。最悪の場合、3回の比較が必要です。

HashSet<int> serialNumAlreadyExisted = new HashSet<int>(); 

serialNumAlreadyExisted.Add(1); 
serialNumAlreadyExisted.Add(2); 
serialNumAlreadyExisted.Add(3); 

var duplicateRows = 
    (from row in dt.AsEnumerable() 
    where row.Field<int>("ID") == varID && 
      serialNumAlreadyExisted.Contains(row.Field<string>("SERIAL_NUMBER")) 
    select row).ToList(); 
1

行の数が増加するにつれて、あなたはそれが原因、それは次のコードを使用して番号を検索しようとすると、現在行われているリニアサーチにパフォーマンスが遅く見つける:

serialNumAlreadyExisted.Any(sr => sr == row.Field<string>("SERIAL_NUMBER")) 

Currnt複雑さO(n^2), to make it O(n)、それはあなたが次のコードであると仮定すると、var serialNumAlreadyExisted = [1,2,3];

のうちの辞書を作成するために、あなたは

012特に辞書値、それを改善することができます可能です次のように
var testDictionary = serialNumAlreadyExisted.ToDictionary(x=>x,x=>x); 

最終的なコードはなります:

var duplicateRows = 
    (from row in dt.AsEnumerable() 
    where row.Field<int>("ID") == varID && 
      testDictionary.ConatinsKey(row.Field<string>("SERIAL_NUMBER")) 
    select row).ToList(); 
1

まず、データテーブルに対してlinqingを実行します。これは、すべてのレコードがメモリ内にあることを意味します。したがって、ロジックをストアドプロシージャに移動してserialNumAlreadyExistedをターゲットテーブルに追加すると、パフォーマンスが大幅に向上します。しかし、datatabaleタグを使用している間は、オプションではないようです。

次に、serialNumAlreadyExistedはint配列なので、どのように比較するとstring

しかし、あなたの短いスニペットでは、あまりオプションはありません。AnyまたはContainsを使用するか、またはメモリ内のデータを結合することで、それほど違いはありません。 serialNumAlreadyExistedHashSetを使用すると少し役に立ちます。しかし、再度言いますと、結合をストアドプロシージャに移動すると、その違いが表示されます。

関連する問題