【问题标题】:LINQ Where clause constant expression optimizationLINQ Where 子句常量表达式优化
【发布时间】:2021-05-16 04:17:35
【问题描述】:

我重写了一些数据库访问代码,以节省一些周期。我的主要目标是尽可能多地对我的 LINQ 查询进行服务器端评估。 为了这样做,我替换了这个:

data = ...some LINQ...
if(condition){
    data = data.Where(element => filter-condition)
}

用这个:

data = ...some LINQ...
.Where(element => !condition || filter-condition)

condition 在这种情况下是一个不依赖于当前元素的表达式。所以你可以说它在整个查询过程中实际上是一个常数,因为它总是对data 中的所有元素计算为真,或者对所有元素计算为假。

另一方面,filter-condition 是一个依赖于当前元素的表达式,正如您对通常的 Where 子句条件所期望的那样。

这种优化就像一个魅力,因为它可以在数据库上的 SQL 中进行服务器端评估,并且 LINQ to SQL 编译器足够智能,甚至可以在我的 condition 评估为 false 时短路生成的 SQL。 我的问题是,如果没有在服务器端的 SQL 中评估此代码会发生什么。可以说我会做以下事情:

data = ...some LINQ...
.AsEnumerable()    //Enforces client-side query evaluation
.Where(element => !condition || filter-condition)

现在我的 Where 子句在客户端进行评估,这在功能方面不是问题。当然,客户端执行的性能较弱。但是我事先做的自定义优化呢?为我的数据序列中的每个元素评估 condition 是否存在性能损失?还是客户端上的 LINQ 也足够智能,可以将“常量”表达式 condition 短路?

【问题讨论】:

  • “因为它可以在数据库上的 SQL 中启用服务器端评估”是什么意思?仅当需要在客户端上实现 Linq 查询时(例如 var list = myquery.ToList()),才将 Linq 查询发送到数据库。否则,您可以随意修改它们,除非需要,否则不会发生任何事情。
  • 在第二种情况下,它们将受到 short-circuiting 的约束,因为它们的标准是 AND/OR 运算符。但仍会执行对 lambda 本身的调用。
  • @MarkoJuvančič 你是对的。查询仅在使用其结果后才会执行。但是 LINQ 精心设计了它的 SQL,因此尽可能多的过滤和映射已经通过数据库上的 SQL 查询完成。但是您可以在 LINQ 查询中使用无法转换为 SQL 的函数。在数据库服务器回答 SQL 查询之后,必须在客户端上评估查询的这些部分。这种机制通常对程序员来说是完全不可见的。但是您可以通过查看提供给服务器的 SQL 查询来检查它

标签: entity-framework linq linq-to-sql


【解决方案1】:

或者客户端的 LINQ 是否也足够智能,可以将“常量”表达式条件短路?

有点。 || 总是在 C# 中获得短路评估,但客户端上的 LINQ 没有任何类型的查询优化器,因此将为每个实体评估 !condition || filter-condition 谓词。

【讨论】:

    猜你喜欢
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-30
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    • 2021-11-10
    相关资源
    最近更新 更多