web-dev-qa-db-ja.com

LINQ関数の順序は重要ですか?

基本的に、質問のように... LINQ関数の順序は、 パフォーマンス?明らかに、結果はまだ同じでなければなりません...

例:

myCollection.OrderBy(item => item.CreatedDate).Where(item => item.Code > 3);
myCollection.Where(item => item.Code > 3).OrderBy(item => item.CreatedDate);

どちらも同じ結果を返しますが、LINQの順序が異なります。一部のアイテムを並べ替えると結果が異なることに気づき、それらについては気にしません。同じ結果を得るために、順序付けがパフォーマンスに影響を与える可能性があるかどうかを知ることが私の主な関心事です。そして、私が行った2つのLINQ呼び出し(OrderBy、Where)だけでなく、すべてのLINQ呼び出しについてもです。

114
michael

使用しているLINQプロバイダーによって異なります。 LINQ to Objectsの場合、確かにhugeの違いが生じる可能性があります。実際に持っていると仮定します:

var query = myCollection.OrderBy(item => item.CreatedDate)
                        .Where(item => item.Code > 3);

var result = query.Last();

wholeコレクションをソートし、-thenフィルタリングする必要があります。 100万個のアイテムがあり、そのうちの1つだけが3を超えるコードを持っている場合、破棄される結果の順序付けに多くの時間を費やすことになります。

それを逆の操作と比較して、最初にフィルタリングします。

var query = myCollection.Where(item => item.Code > 3)
                        .OrderBy(item => item.CreatedDate);

var result = query.Last();

今回は、フィルター処理された結果のみを並べ替えます。「フィルターに一致する単一のアイテム」のサンプルの場合は、時間と空間の両方ではるかに効率的です。

couldクエリが正しく実行されるかどうかにも違いがあります。検討してください:

var query = myCollection.Where(item => item.Code != 0)
                        .OrderBy(item => 10 / item.Code);

var result = query.Last();

それは問題ありません。0で除算されることは決してないでしょう。しかし、順序付けbeforeフィルタリングを実行すると、クエリは例外をスローします。

147
Jon Skeet

はい。

しかし、正確にはwhatパフォーマンスの違いは、基になる式ツリーがLINQプロバイダーによってどのように評価されるかによって異なります。

たとえば、LINQ-to-XMLの場合、クエリは2回目に(WHERE句を最初に)速く実行できますが、LINQ-to-SQLの場合、初回は高速です。

パフォーマンスの違いを正確に知るには、アプリケーションのプロファイルを作成する必要があります。ただし、このような場合でも、時期尚早の最適化は通常は努力する価値はありません。LINQのパフォーマンス以外の問題がより重要であることに気付くかもしれません。

17
Jeremy McGee

あなたの特定の例ではcanはパフォーマンスに違いをもたらします。

最初のクエリ:OrderBy呼び出しは、Codeが3以下の項目を含めて、全体ソースシーケンスを反復処理する必要があります。また、Where句はentire順序のシーケンスを繰り返す必要があります。

2番目のクエリ:Where呼び出しは、Codeが3より大きいアイテムのみにシーケンスを制限します。OrderBy呼び出しは、Where呼び出しによって返された削減されたシーケンスのみをトラバースする必要があります。

5
LukeH

Linq-To-Objects内:

ソートはかなり遅く、O(n)メモリを使用します。一方、Whereは比較的高速で、定数メモリを使用します。そのため、最初にWhereを実行すると高速になり、大規模なコレクションの場合は大幅に高速になります。

大きなオブジェクトヒープへの割り当て(それらのコレクションと合わせて)は、私の経験では比較的高価であるため、メモリ負荷の軽減も重要になる可能性があります。

3
CodesInChaos

検討するときは注意が必要です。 どうやって LINQクエリを最適化します。たとえば、LINQの宣言バージョンを使用して次のことを行う場合:

public class Record
{
    public string Name { get; set; }
    public double Score1 { get; set; }
    public double Score2 { get; set; }
}


var query = from record in Records
            order by ((record.Score1 + record.Score2) / 2) descending
            select new
                   {
                       Name = record.Name,
                       Average = ((record.Score1 + record.Score2) / 2)
                   };

何らかの理由で、最初に平均を変数に格納してクエリを「最適化」することに決めた場合、希望する結果が得られません。

// The following two queries actually takes up more space and are slower
var query = from record in Records
            let average = ((record.Score1 + record.Score2) / 2)
            order by average descending
            select new
                   {
                       Name = record.Name,
                       Average = average
                   };

var query = from record in Records
            let average = ((record.Score1 + record.Score2) / 2)
            select new
                   {
                       Name = record.Name,
                       Average = average
                   }
            order by average descending;

オブジェクトに宣言型LINQを使用する人は少ないと思いますが、考えるのに適した食べ物です。

1
m-y

明らかに、結果はまだ同じでなければなりません...

これは実際には当てはまらないことに注意してください。特に、次の2行では結果が異なります(ほとんどのプロバイダー/データセットの場合)。

myCollection.OrderBy(o => o).Distinct();
myCollection.Distinct().OrderBy(o => o);

それは関連性に依存します。 Code = 3のアイテムが非常に少ない場合、次の注文は少量のコレクションで機能し、日付順に注文を取得します。

一方、同じCreatedDateのアイテムが多数ある場合、次の注文は、より大きなコレクションのセットで機能し、日付順に注文を取得します。

したがって、どちらの場合もパフォーマンスに違いがあります

0
Pankaj Upadhyay