2012-02-24 11 views
8

私は異なる順序で実行する操作は、次のスロークエリの違いなど、さまざまなパフォーマンスが得られることを理解:LINQを使用する場合、述語の順序が重要ですか?

List<TestItem> fastResults = items.Where(item => item.IntItem == 100) 
            .OrderBy(item => item.StringItem) 
            .ToList(); 

しかし、それは私ではありません。

List<TestItem> slowResults = items.OrderBy(item => item.StringItem) 
            .Where(item => item.IntItem == 100) 
            .ToList(); 

と1本速いです質問:

私の質問は、 LINQ述語に変換します。この場合のようにWhere句を使用すると、次のようになります。

List<TestItem> results = items.Where(item => item.Item1 == 12 && 
              item.Item2 != null && 
              item.Item2.SubItem == 65 && 
              item.Item3.Equals(anotherThingy)) 
           .ToList(); 

引数の順序は関係ありませんか?たとえば、.Equalsを最初に実行すると、Item1 == 12の整数評価がはるかに高速な操作であるため、全体的にクエリが遅くなることが予想されます。

注文が問題であれば、どれくらい重要ですか?もちろん、.Equalsのようなメソッドを呼び出すのはおそらく数倍の整数を比較した場合よりもはるかに大きなスローダウンですが、LINQの動作が遅い場合に比べてパフォーマンスが低下しますか? LINQは多くのメソッド呼び出しを行いますが、実際にはエスケープが問題になります。オーバーライドされない限り、ネイティブフレームワークコードを実行します。一方、標準的なMSILメソッド呼び出しは大幅に遅くなるでしょうか?

また、このクエリでは、これをスピードアップしている可能性のある他のコンパイラの最適化がありますか?

ありがとうございました。 Brett

+2

LINQ to what? – SLaks

+0

私はLINQ to Objectsを考えていましたが、その質問はLINQ to SQLにとってさらに重要だと思います。 – Brett

+2

LINQ____はわかりませんが、他の短絡言語の場合は、評価する式が確実に真または偽になると、残りの述語は安全に破棄できるため、順序は重要です。たとえば、式 '(1 == 1 || x == 3)'では、結果が何であっても式は真となるため、 'x == 3'は評価されません。同様の簡単な例は '(1 == 0 && x == 3)'で、 '1 == 0'の後に偽であると判明した場合、式が真となる方法がないので終了します。申し訳ありませんが、これはあなたが探しているものではない場合! – prelic

答えて

13

答えはLINQプロバイダごとに異なります。特に、物語はLINQ to Objectsと非常に異なり、LINQ to Entitiesと言います。

LINQ to Objectsでは、Where演算子はフィルタをFunc < TSource、bool として受け入れます。 Func <、>はデリゲートなので、ここでは関数ポインタと考えることができます。オブジェクトへのLINQでは、クエリがこれに相当します

static void Main() { 
    List<TestItem> results = items.Where(MyFilter).ToList(); 

static boolean MyFilter(TestItem item) { 
    return item.Item1 == 12 && 
     item.Item2 != null && 
     item.Item2.SubItem == 65 && 
     item.Item3.Equals(anotherThingy) 
} 

注意すべき主なものは、myFilterを、通常のC#メソッドであるので、通常のC#のルールが& &の短絡行動を含め、適用されることです。その結果、条件はあなたが書いた順に評価されます。 LINQ to Objectsは、さまざまな入力要素でMyFilterを呼び出すことができますが、MyFilterの機能を変更することはできません。 SQLのエンティティとLINQのLINQで

、オペレータは式<のFunc < TSOURCE、ブール> >としてフィルタを受け入れるところ。ここで、フィルターは式を記述するデータ構造としてWhere演算子に渡されます。その場合、LINQプロバイダはデータ構造(「式ツリー」)を調べ、解釈方法を決定するのはLINQプロバイダに任されます。

LINQ to EntitiesおよびLINQ to SQLの場合、式ツリーはSQLに変換されます。次に、クエリの実行方法を決定するのはデータベースサーバーの責任です。サーバーは条件を並べ替えることは間違いありませんし、さらに大幅な最適化を行うこともできます。たとえば、SQLテーブルに条件で参照されている列の1つにインデックスが含まれている場合、サーバーはインデックスを使用してその特定の条件部分に一致しない行を探すこともできます。

+0

詳細な回答ありがとうございます! – Brett

関連する問題