慢速AsQueryable()和用于IQueryable和IEnumerable的通用方法

本文关键字:方法 IEnumerable 用于 AsQueryable 慢速 IQueryable | 更新日期: 2023-09-27 18:26:39

我想对IQueryable和IEnumerable使用一种方法:

public static IEnumerable<T> WhereEx<T>(this IEnumerable<T> query, Expression<Func<T, bool>> exp)
{
   return query.AsQueryable().Where(exp);
}
public static IEnumerable<Ship> GetShipsSome(this IEnumerable<Ship> query)
{
   return query.WhereEx(x => x.Id > 150);
}

使用:带IQueryable:

var x = context.Set<Ships>().AsNoTracking().GetShipsSome(); //from DB

带IEnumerable:

var x = shipsInRam.GetShipsSome(); //from collection in ram(list)

但是,如果我使用IEnumerable(从ram中的集合获取),由于AsQueryable()转换集合,我的代码比IEnumerable.Where慢。如何优化我的代码?

修复:FirstOrDefault而不是Where

慢速AsQueryable()和用于IQueryable和IEnumerable的通用方法

在阅读了您的声明后,我并不信服,所以我编写了一个基准测试。

var list = Enumerable.Range(1, 1000000).ToList();
for(var i = 0; i < 100; i++)
{
    var warmupA = list.WhereEx(a => a > 500000).ToList();
    var warmupB = list.Where(a => a > 500000).ToList();;
    var warmupC = list.WhereExCompile(a => a > 500000).ToList();;
}
var sw = new Stopwatch();
sw.Start();
for(var i = 0; i < 100; i++)
{
    var wherexresult =  list.WhereEx(a => a > 500000).ToList();
}
sw.Stop();
var wherextime = sw.ElapsedMilliseconds;
sw = new Stopwatch();
sw.Start();
for(var i = 0; i < 100; i++)
{
    var whereresult =  list.Where(a => a > 500000).ToList();
}
sw.Stop();
var whertime = sw.ElapsedMilliseconds;
sw = new Stopwatch();
sw.Start();
for(var i = 0; i < 100; i++)
{
    var whereexcompileresult =  list.WhereExCompile(a => a < 500000).ToList();
}
sw.Stop();
var whereexcompiletime = sw.ElapsedMilliseconds;
wherextime.Dump();
whertime.Dump();
whereexcompiletime.Dump();
public static class a  {
    public static IEnumerable<T> WhereExCompile<T>(this IEnumerable<T> query, Expression<Func<T, bool>> exp)
    {
        return query.AsQueryable().Where(exp);
    }
    public static IEnumerable<T> WhereEx<T>(this IEnumerable<T> query, Expression<Func<T, bool>> exp)
    {
        return query.Where(exp.Compile());
    }
}

这给出了结果:

list.WhereEx(a => a > 500000) = 1320ms
list.Where(a => a > 500000) = 1572ms
list.WhereExCompile(a => a < 500000) = 1284ms

启用优化后:

list.WhereEx(a => a > 500000) = 1285ms
list.Where(a => a > 500000) = 1372ms
list.WhereExCompile(a => a < 500000) = 1263ms

差异可以忽略不计(每次运行100000000次,每次耗时不到1.5秒)。如果有什么不同的话,你的方法比.Where()。那么,您从哪里得到代码需要优化的想法呢?

您应该返回IQueryable<T>而不是IEnumerable<T>,如果您获取的记录只是为了向用户显示,并且不会更改任何这些记录,为了获得更好的性能,您可以使用AsNoTracking()获取记录。

还有一件事,你必须像这个一样使用AsQueryable()

return query.Where(exp).AsQueryable();

相关文章: