52

次の LINQ to SQL クエリがあるとします。

var test = from i in Imports
           where i.IsActive
           select i;

解釈された SQL ステートメントは次のとおりです。

SELECT [t0].[id] AS [Id] .... FROM [Imports] AS [t0] WHERE [t0].[isActive] = 1

select で SQL に変換できないアクションを実行したいとします。AsEnumerable()これを達成するための従来の方法は、それを実行可能なオブジェクトに変換することであると私は理解しています。

この更新されたコードを考えると:

var test = from i in Imports.AsEnumerable()
           where i.IsActive
           select new 
           { 
               // Make some method call 
           };

そして更新されたSQL:

SELECT [t0].[id] AS [Id] ... FROM [Imports] AS [t0] 

実行された SQL ステートメントに where 句がないことに注意してください。

これは、「インポート」テーブル全体がメモリにキャッシュされるということですか? テーブルに大量のレコードが含まれていると、パフォーマンスがまったく低下しますか?

ここで舞台裏で実際に何が起こっているのかを理解するのを手伝ってください。

4

4 に答える 4

41

AsEnumerableの理由は、

AsEnumerable(TSource)(IEnumerable(TSource)) を使用して、シーケンスが IEnumerable(T) を実装しているが、別のパブリック クエリ メソッドのセットを使用できる場合、クエリの実装を選択できます。

Whereそのため、以前にメソッドを呼び出していたときは、 とは別のWhereメソッドを呼び出していましたIEnumerable.Where。そのWhereステートメントは、LINQ が SQL に変換するためのものでした。新しいステートメントは、WhereIEnumerable受け取り、IEnumerableそれを列挙して、一致する項目を生成するステートメントです。これは、異なる SQL が生成されている理由を説明しています。Whereコードの 2 番目のバージョンで拡張機能が適用される前に、テーブルはデータベースから完全に取得されます。これは、テーブル全体がメモリ内にある必要があるか、さらに悪いことに、テーブル全体がサーバー間を移動する必要があるため、深刻なボトルネックを引き起こす可能性があります。SQL サーバーが実行できるWhereようにし、最適な処理を実行します。

于 2010-07-22T16:57:45.197 に答える
8

列挙が列挙される時点で、データベースが照会され、結果セット全体が取得されます。

部分的および部分的なソリューションが道になる可能性があります。検討

var res = (
    from result in SomeSource
    where DatabaseConvertableCriterion(result)
    && NonDatabaseConvertableCriterion(result)
    select new {result.A, result.B}
);

また、NonDatabaseConvertableCriterion には結果のフィールド C が必要であるとしましょう。NonDatabaseConvertableCriterion はその名前が示すように機能するため、列挙として実行する必要があります。ただし、次のことを考慮してください。

var partWay =
(
    from result in SomeSource
    where DatabaseConvertableCriterion(result)
    select new {result.A, result.B, result.C}
);
var res =
(
    from result in partWay.AsEnumerable()
    where NonDatabaseConvertableCriterion select new {result.A, result.B}
);

この場合、 res が列挙、クエリ、またはその他の方法で使用されると、可能な限り多くの作業がデータベースに渡され、ジョブを続行するのに十分な量が返されます。すべての作業をデータベースに送信できるように書き直すことは本当に不可能であると仮定すると、これは適切な妥協点になる可能性があります。

于 2010-07-23T18:15:47.883 に答える
6

には 3 つの実装がありAsEnumerableます。

DataTableExtensions.AsEnumerable

a を拡張しDataTableIEnumerableインターフェイスを提供し、 に対して Linq を使用できるようにしますDataTable

Enumerable.AsEnumerable<TSource>ParallelEnumerable.AsEnumerable<TSource>

このメソッドは、ソースのコンパイル時の型をそれ自体に実装するAsEnumerable<TSource>(IEnumerable<TSource>)型から変更する以外に効果はありません。IEnumerable<T>IEnumerable<T>

AsEnumerable<TSource>(IEnumerable<TSource>)シーケンスが実装されている場合にクエリの実装を選択するために使用できますが、 IEnumerable<T>使用可能なパブリック クエリ メソッドのセットも異なります。たとえば、 、、など の独自のメソッドTableを実装 して持つジェネリック クラスがある場合、を呼び出すと、 のパブリックメソッドが 呼び出されます。データベース テーブルを表す型には、述語引数を式ツリーとして受け取り、そのツリーをリモート実行用の SQL に変換するメソッドを含めることができ ます。述語がローカル メソッドを呼び出すなどの理由でリモート実行が望ましくない場合は、そのメソッドを使用してカスタム メソッドを非表示にし、代わりに標準のクエリ演算子を使用できるようにすることができます。IEnumerable<T>WhereSelectSelectManyWhereWhereTableTableWhereAsEnumerable<TSource>

言い換えると。

私が持っている場合

IQueryable<X> sequence = ...;

Entity Framework のような LinqProvider から

sequence.Where(x => SomeUnusualPredicate(x));

そのクエリが構成され、サーバー上で実行されます。EntityFramework は SQL への変換方法を認識していないため、これは実行時に失敗しSomeUnusualPredicateます。

代わりに Linq to Objects を使用してステートメントを実行する場合は、次のようにします。

sequence.AsEnumerable().Where(x => SomeUnusualPredicate(x));

これで、サーバーはすべてのデータを返し、Enumerable.WhereLinq からオブジェクトへの変換がクエリ プロバイダーの実装の代わりに使用されます。

Entity Framework が を解釈する方法を知らなくても構いませんSomeUnusualPredicate。私の関数が直接使用されます。(ただし、すべての行がサーバーから返されるため、これは非効率的なアプローチになる可能性があります。)

于 2014-05-19T09:23:01.693 に答える
2

AsEnumerable は、使用する拡張メソッドをコンパイラに伝えるだけだと思います (この場合、IQueryable の代わりに IEnumerable 用に定義されたメソッド)。クエリの実行は、ToArray を呼び出すか列挙するまで延期されます。

于 2010-07-22T16:59:16.093 に答える