代码之家  ›  专栏  ›  技术社区  ›  Elastic Lamb

使用LINQ表达式时,SQL查询生成效率低下

  •  0
  • Elastic Lamb  · 技术社区  · 6 年前

    dbContext 是SQL Server数据库上下文,并且 Examples DbSet :

    this.dbContext.Examples.Take(5).ToList();
    Enumerable.Take(this.dbContext.Examples, 5).ToList();
    

    SELECT TOP(5) * FROM Examples
    

    但是,第二行首先获取所有行并应用 Take 接线员。为什么?

    由于我使用表达式来构建动态lambda,所以必须使用第二种方法( Enumerable.Take ):

    var call = Expression.Call(
        typeof(Enumerable),
        "Take",
        new[]{ typeof(Examples) },
        contextParam,
        Expression.Constant(5)
    );
    

    不幸的是,第一种方法在处理表达式时不起作用,而且程序的当前体系结构迫使我动态地构建lambda。

    为什么第二种方法会获取所有行?我如何阻止它以便在表达式中有效地使用它?

    0 回复  |  直到 6 年前
        1
  •  3
  •   StriplingWarrior    6 年前

    你调用的不是同一个方法。第一行是调用 Queryable.Take Enumerable.Take .

    因为 DbSet IQueryable<> 和 IEnumerable<> ,但是 工具 &IEnumerable> ,编译器处理 IQueryable<>; a型更为具体。所以当它解决 Take 要调用的扩展方法,它确定 Queryable.Take(...) IQueryable<>; 作为第一个参数。

    这很重要,因为 接口允许将LINQ查询构建为表达式树,并将其计算到SQL中。当你开始治疗 IQueryable<>; 作为一个 ,则会丢失该行为并切换到只能迭代在此之前生成的任何查询的结果。

    Queryable.Take(this.dbContext.Examples, 5).ToList();
    

    或者这个:

    var call = Expression.Call(
        typeof(Queryable),
        "Take",
        new[]{ typeof(Examples) },
        contextParam,
        Expression.Constant(5)
    );
    
        2
  •  1
  •   Jakub Kozera    6 年前

    因为在第一个语句中

    dbContext.Examples.Take(5).ToList(); -您正在iquelable接口上IV冲剂.Take(5),LINQ到SQL提供程序可以在该接口上针对数据库执行适当的SQL语句。

    如果需要在数据库端进行查询,则必须在IQuerable接口实例上构造查询。

    Enumerable.Take 是IEnumarble引用,则Take方法的执行将在内存中进行,在您从数据库获取所有数据之后

        3
  •  0
  •   Tanvir Jewel    6 年前

    "this.dbContext.Examples“那就得到所有的数据可枚举。Take过滤并从中取出前5个。