我知道 IQueryable 和 IEnumerable 之间的区别,并且我知道 Linq To Objects 通过 IEnumerable 接口支持集合。
令我困惑的是,当集合转换为 IQueryable 时,查询的执行速度是原来的两倍。
假设l是List类型的填充对象,如果通过l.AsQueryable()将列表l转换为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 ) );
}
运行此测试(使用 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更快。试运行次数增加?
- 使用IQueryable而不是IEnumerable会受到惩罚吗?
我问这些问题是因为我想知道将哪一个用于我的存储库接口。现在他们查询内存中的集合(Linq to Objects),但将来这可能是一个 SQL 数据源。如果我现在使用IQueryable设计存储库类,我以后可以轻松地切换到 Linq to SQL。但是,如果存在性能损失,那么在不涉及 SQL 的情况下坚持使用IEnumerable似乎更明智。