我知道IQueryable和IEnumerable之间的区别,也知道通过IEnumerable接口支持Linq To Objects的集合。
令我困惑的是,当集合转换为IQueryable时,查询的执行速度会快两倍。
设l是一个填充好的List对象,则如果列表l通过l.AsQueryable()转换为IQueryable,则linq查询的速度会变快一倍。
我在VS2010SP1和.NET 4.0上编写了一个简单的测试来证明这一点。
令我困惑的是,当集合转换为IQueryable时,查询的执行速度会快两倍。
设l是一个填充好的List对象,则如果列表l通过l.AsQueryable()转换为IQueryable,则linq查询的速度会变快一倍。
我在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 ) );
}
运行此测试(其中将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
重复测试,但更改顺序(即首先测量IQueryable,然后是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 更快?
- 使用 IQueryable 是否会产生影响?
我提出这些问题是因为我想知道在存储库接口中应该使用哪一个。目前它们在内存中查询集合(Linq to Objects),但未来可能会是 SQL 数据源。如果我现在使用 IQueryable 设计存储库类,以后可以轻松切换到 Linq to SQL。但是,如果存在性能惩罚,那么在没有 SQL 的情况下坚持使用 IEnumerable 似乎更明智。