2

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

正如预期的那样,性能以相同的顺序进行,但在分析后两者时我注意到了一些奇怪的东西。

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

本地 SQLExpress 数据库;表称为'foreignTable',ColumnA是int,主键(索引);ColumnB 是一个随机整数。

Func<testingDatabaseEntities1, int, int> 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 吸力的常规 Linq?

4

2 回答 2

5

您正在比较的查询不一样。第一个已编译的查询返回一个属性,没有其他任何内容。它永远不会返回任何不同的东西。第二个返回您取消引用然后访问其属性的实体实例。当查询执行时,它无法知道您打算只查看一个属性。

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

var b = (from e in entity.foreignTable.
         where ColumnA == searchForMe
         select new 
         {
            ColumnB = e.ColumnB
         }).FirstOrDefault().ColumnB;
于 2009-03-31T17:43:24.277 回答
3

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

在这种特定情况下,您想要执行以下操作:

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

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

于 2009-03-31T17:07:53.333 回答