【发布时间】:2011-05-08 02:31:58
【问题描述】:
今天我发现 Entity Framework 在它生成的 SQL 中添加了一个不必要的子查询。我开始挖掘我的代码,试图缩小它可能来自哪里。 A(很长)稍后我指出是什么原因造成的。但是现在我比开始时更困惑,因为我不知道为什么会导致它。
基本上我发现,在某些情况下,只需将常量转换为变量就可以改变 Entity Framework 生成的 SQL。我已将所有内容压缩到最低限度,并将其打包到一个小控制台应用程序中:
using System;
using System.Data.Entity;
using System.Linq;
class Program
{
private static readonly BlogContext _db = new BlogContext();
static void Main(string[] args)
{
const string email = "foo@bar.com";
var comments = from c in _db.Comments
where c.Email == email
select c;
var result = (from p in _db.Posts
join c in comments on p.PostId equals c.PostId
orderby p.Title
select new { p.Title, c.Content });
Console.WriteLine(result);
}
}
public class BlogContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
}
public class Comment
{
public int CommentId { get; set; }
public int PostId { get; set; }
public string Email { get; set; }
public string Content { get; set; }
}
这显示了以下输出,非常完美:
SELECT
[Extent1].[PostId] AS [PostId],
[Extent1].[Title] AS [Title],
[Extent2].[Content] AS [Content]
FROM [dbo].[Posts] AS [Extent1]
INNER JOIN [dbo].[Comments] AS [Extent2] ON [Extent1].[PostId] = [Extent2].[PostId]
WHERE N'foo@bar.com' = [Extent2].[Email]
ORDER BY [Extent1].[Title] ASC
现在,如果我将 email 设为变量:
/*const*/ string email = "foo@bar.com";
输出发生了根本性的变化:
SELECT
[Project1].[PostId] AS [PostId],
[Project1].[Title] AS [Title],
[Project1].[Content] AS [Content]
FROM ( SELECT
[Extent1].[PostId] AS [PostId],
[Extent1].[Title] AS [Title],
[Extent2].[Content] AS [Content]
FROM [dbo].[Posts] AS [Extent1]
INNER JOIN [dbo].[Comments] AS [Extent2] ON [Extent1].[PostId] = [Extent2].[PostId]
WHERE [Extent2].[Email] = @p__linq__0
) AS [Project1]
ORDER BY [Project1].[Title] ASC
附带说明,LINQ to SQL 似乎没有这样做。我知道忽略这一点可能没问题,因为两个命令都返回相同的数据。但我非常好奇为什么会发生这种情况。直到今天,我一直有一个(也许是假的?)印象,将常量转换为变量总是安全的,只要值保持不变(在这种情况下确实如此)。所以我不得不问...
为什么一个看似微不足道的变化会导致生成的 SQL 产生如此大的差异?
更新:
为了清楚起见,我的问题不在于 email 的值是第一个查询中的硬编码值和第二个查询中的变量(这在世界上很有意义)。我的问题是为什么变量版本会导致额外的子查询。
谢谢!
【问题讨论】:
-
我不会担心查询的 form - SQL 旨在表达您想要的结果,而不是实现它们的过程 - 我如果查询计划有很大或任何差异,我会感到惊讶。优化器应该产生大致相同的查询计划。
标签: c# entity-framework entity-framework-4 linq-to-entities code-first