私は IQueryable と IEnumerable の違いを知っており、コレクションが IEnumerable インターフェイスを介して Linq To Objects によってサポートされていることを知っています。
私が困惑しているのは、コレクションが IQueryable に変換されると、クエリが 2 倍の速さで実行されることです。
lをList型の塗りつぶされたオブジェクトとすると、リストlがl.AsQueryable ()を介してIQueryableに変換される場合、linq クエリは 2 倍高速になります。
これを示す VS2010SP1 と .NET 4.0 を使用した簡単なテストを作成しました。
private void Test()
{
const int numTests = 1;
const int size = 1000 * 1000;
var l = new List<int>();
var resTimesEnumerable = new List<long>();
var resTimesQueryable = new List<long>();
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
for ( int x=0; x<size; x++ )
{
l.Add( x );
}
Console.WriteLine( "Testdata size: {0} numbers", size );
Console.WriteLine( "Testdata iterations: {0}", numTests );
for ( int n = 0; n < numTests; n++ )
{
sw.Restart();
var result = from i in l.AsEnumerable() where (i % 10) == 0 && (i % 3) != 0 select i;
result.ToList();
sw.Stop();
resTimesEnumerable.Add( sw.ElapsedMilliseconds );
}
Console.WriteLine( "TestEnumerable" );
Console.WriteLine( " Min: {0}", Enumerable.Min( resTimesEnumerable ) );
Console.WriteLine( " Max: {0}", Enumerable.Max( resTimesEnumerable ) );
Console.WriteLine( " Avg: {0}", Enumerable.Average( resTimesEnumerable ) );
for ( int n = 0; n < numTests; n++ )
{
sw.Restart();
var result = from i in l.AsQueryable() where (i % 10) == 0 && (i % 3) != 0 select i;
result.ToList();
sw.Stop();
resTimesQueryable.Add( sw.ElapsedMilliseconds );
}
Console.WriteLine( "TestQuerable" );
Console.WriteLine( " Min: {0}", Enumerable.Min( resTimesQueryable ) );
Console.WriteLine( " Max: {0}", Enumerable.Max( resTimesQueryable ) );
Console.WriteLine( " Avg: {0}", Enumerable.Average( resTimesQueryable ) );
}
このテストを (will numTests == 1 および 10 で) 実行すると、次の出力が生成されます。
Testdata size: 1000000 numbers
Testdata iterations: 1
TestEnumerable
Min: 44
Max: 44
Avg: 44
TestQuerable
Min: 37
Max: 37
Avg: 37
Testdata size: 1000000 numbers
Testdata iterations: 10
TestEnumerable
Min: 22
Max: 29
Avg: 23,9
TestQuerable
Min: 12
Max: 22
Avg: 13,9
テストを繰り返して順序を入れ替えると (つまり、最初に IQuerable を測定し、次に IEnumerable を測定する)、異なる結果が得られます。
Testdata size: 1000000 numbers
Testdata iterations: 1
TestQuerable
Min: 75
Max: 75
Avg: 75
TestEnumerable
Min: 25
Max: 25
Avg: 25
Testdata size: 1000000 numbers
Testdata iterations: 10
TestQuerable
Min: 12
Max: 28
Avg: 14
TestEnumerable
Min: 22
Max: 26
Avg: 23,4
ここに私の質問があります:
- 私は何を間違っていますか?
- IQueryableテストの後にテストを実行すると、 IEnumerableの方が速いのはなぜですか?
- いいえの場合、 IQueryableの方が速いのはなぜですか。試運転の回数は増えていますか?
- IEnumerableの代わりにIQueryableを使用するとペナルティはありますか?
これらの質問をするのは、自分のリポジトリ インターフェイスにどれを使用するかを考えていたからです。現在、メモリ内のコレクション (Linq to Objects) をクエリしていますが、将来的にはこれがSQL データソースになる可能性があります。IQueryableを使用してリポジトリ クラスを設計すると、後から Linq to SQL に簡単に切り替えることができます。ただし、パフォーマンスが低下する場合は、SQL を使用せずにIEnumerableに固執する方が賢明なようです。