CompiledQuery与Plain Linq SQL生成

所以我正在对我的SQLServer数据库的不同方法进行一些分析。 我做了vanilla TSQL,CompiledQuery和一个非编译的Linq语句。

正如预期的那样,表演按照相同的顺序进行,但是在对后两者进行剖析时我发现了一些好奇的东西。

CompiledQuery生成的SQL比普通旧语句生成的SQL要好得多。

本地SQLExpress数据库; table被称为’foreignTable’,ColumnA是int,主键(索引); ColumnB是随机int。

Func GetByPK = CompiledQuery.Compile((testingDatabaseEntities1 ft, int key) => (ft.foreignTable.Where(x => x.ColumnA == key).FirstOrDefault().ColumnB)); 

生成

 SELECT [Project1].[ColumnB] AS [ColumnB] FROM ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1] LEFT OUTER JOIN (SELECT TOP (1) [Extent1].[ColumnB] AS [ColumnB] FROM [dbo].[foreignTable] AS [Extent1] WHERE [Extent1].[ColumnA] = @p__linq__1 ) AS [Project1] ON 1 = 1 

对于生成的代码,这真的不是可怕了。

但是当我做普通的Linq声明时:

 entity.foreignTable.Where(x => x.ColumnA == searchForMe).FirstOrDefault().ColumnB 

它会产生:

 SELECT [Limit1].[C1] AS [C1], [Limit1].[ColumnA] AS [ColumnA], [Limit1].[ColumnB] AS [ColumnB], [Limit1].[FKColumn] AS [FKColumn] FROM ( SELECT TOP (1) [Extent1].[ColumnA] AS [ColumnA], [Extent1].[ColumnB] AS [ColumnB], [Extent2].[FKColumn] AS [FKColumn], 1 AS [C1] FROM [dbo].[foreignTable] AS [Extent1] LEFT OUTER JOIN (SELECT [Table_2].[FKColumn] AS [FKColumn], [Table_2].[SomeText] AS [SomeText] FROM [dbo].[Table_2] AS [Table_2]) AS [Extent2] ON [Extent1].[ColumnA] = [Extent2].[FKColumn] WHERE [Extent1].[ColumnA] = @p__linq__7 ) AS [Limit1] 

这只是蹩脚的。

所以我想问题是:是否有可能为实体提供与CompiledQuery相同数量的SQL suckiness的常规Linq?

您要比较的查询不一样。 第一个编译的查询返回一个属性而不返回任何其他属性 它永远不会返回任何不同。 第二个返回一个您取消引用然后访问其属性的实体实例。 当查询执行时,它无法知道您只想查看一个属性。

您可以从非编译查询中获取相同SQL的一种方法(未经测试)是投影到匿名类型:

 var b = (from e in entity.foreignTable. where ColumnA == searchForMe select new { ColumnB = e.ColumnB }).FirstOrDefault().ColumnB; 

已编译的查询正在执行额外的工作,因为预计您将多次使用该查询。 如果这就是你所追求的,那么只需坚持编译查询。

在这种特定情况下,您希望:

 entity.foreignTable .Where(x => x.ColumnA == searchForMe) .Select(x=>x.ColumnB) .FirstOrDefault(); 

这不完全相同,但它肯定会使查询更符合您的期望(仅检索ColumnB)。 执行FirstOrDefault将为您提供实例,因此在linq2sql查询之后会发生.ColumnB。 这也会导致行为差异,因为您的版本因空引用而失败,而此新查询将提供ColumnB的默认值(null或特定值取决于ColumnB定义)。