为啥 LINQ-to-Entities 将此查询放在子选择中?

Posted

技术标签:

【中文标题】为啥 LINQ-to-Entities 将此查询放在子选择中?【英文标题】:Why does LINQ-to-Entities put this query in a sub-select?为什么 LINQ-to-Entities 将此查询放在子选择中? 【发布时间】:2012-06-20 23:04:05 【问题描述】:

我有以下 LINQ 查询:

var queryGroups = (from p in db.cl_contact_event
                   select new Groups  inputFileName = p.input_file_name ).Distinct();

运行时转换为以下内容:

SELECT 
[Distinct1].[C1] AS [C1], 
[Distinct1].[input_file_name] AS [input_file_name]
FROM ( SELECT DISTINCT 
       [Extent1].[input_file_name] AS [input_file_name], 
       1 AS [C1]
       FROM [mel].[cl_contact_event] AS [Extent1]
)  AS [Distinct1]

现在我很确定存在子选择的原因是因为我有基本的 LINQ 查询被 () 包围,然后执行 .Distinct() 但我对 LINQ 的了解不够,无法确定这。如果确实如此,有没有办法重组/编码我的查询,以便不会发生子选择?

我知道我可能只是在这里吹毛求疵,但我只是好奇。

【问题讨论】:

是linq-to-sql、linq-to-entities 还是linq-to-nhibernate? @DannyVarod linq-to-entities 我相信,因为我使用的是 EF4,所以我正在查询 Sybase 数据库。 在这种情况下,更改您使用的标签并相应地更新问题的标题。 比较 EF 生成的查询计划和您建议的改进之间的查询计划,看看是否有差异。查询优化器非常聪明。 【参考方案1】:

我根本不会担心这种特殊情况。 SQL Server(很可能是任何企业数据库)无论如何都会优化外部 Select 语句。我认为生成此 SQL 语句的原因是因为这是最通用和可重用的语句。根据我的经验,这总是发生在Distinct()

【讨论】:

【参考方案2】:

在此我怀疑子查询的实际根本原因是匿名类型构造函数。因为您选择的不是已知实体,而是从其他实体值构造的任意对象,所以 EF 解析器需要确保它可以生成准确的字段集——无论是来自单个表、连接表、计算字段还是其他子查询等。表达式树解析器非常擅长尽可能从 LINQ 查询中编写 SQL 语句,但它并不是无所不知的。它以系统的方式处理查询,这将始终产生正确的结果(从某种意义上说,您得到了您所要求的),但并不总是最佳结果。

至于重写查询以消除子选择,首先:我没有看到明显的方法可以消除匿名类型并产生正确的结果。不过,更重要的是,我不会打扰。像 Sybase 这样的现代 SQL 服务器非常聪明——通常比开发人员更聪明——并且非常擅长从查询中生成最佳查询计划。除此之外,EF 喜欢子查询,因为它们是自动编写复杂查询的好方法。即使您的 LINQ 查询没有出现使用它们,您也经常会发现它们。试图从查询中消除它们很快就会成为徒劳的练习。

【讨论】:

感谢您出色而详细的回复。我只是想确定我没有犯任何明显的错误。

以上是关于为啥 LINQ-to-Entities 将此查询放在子选择中?的主要内容,如果未能解决你的问题,请参考以下文章

将日期时间转换为 LINQ-to-entities 查询中的格式化字符串

Linq-to-Entities:带有 WHERE 子句和投影的 LEFT OUTER JOIN

mysql 为啥小表放前面查询时间 比大表放前面查询时间长?

使用 LINQ-to-Entities 搜索时忽略空字符串

如果存在-UPDATE-else-INSERT 与 Linq-to-Entities?

为啥 Instruments 将此报告为内存泄漏?