SQL 服务器中的 EF 核心参数嗅探

EF Core Parameter Sniffing in SQL Server

我一直在观看 Brent Ozar 的培训视频(对我来说是 SQL 大师),他谈到了参数嗅探并说 EF 可以做到这一点,但对于我来说,我无法找到一个有效的例子。我期待看到参数,但它只是创建了这样的 SQL,只是相等,而不是 @p1、@p2。

SELECT [p].[Id], [p].[Body], [p0].[Type]
FROM [Posts] AS [p]
INNER JOIN [PostTypes] AS [p0] ON [p].[PostTypeId] = [p0].[Id]
WHERE ([p].[PostTypeId] = 6) AND ([p].[CreationDate] >= '2011-01-01T00:00:00.000')

我通过搭建他的 Whosebug2013 数据库创建了 DBContext,并在 post 类型上创建了一个外键以获得某种 JOIN。

有谁知道我如何获得使用 EF 进行参数嗅探的示例,因为这每次都会创建一个新的查询计划?

如果我调用存储过程,那么我可以获得参数嗅探。

我的C#代码如下

  var result = ctx.Posts
    .Include(x => x.PostType)
    .Where(x => x.PostTypeId == 6 && x.CreationDate >= new DateTime(2013, 01, 01))
        .Select(x => new {
           Id = x.Id,
           Body = x.Body, 
           Type = x.PostType.Type
         }).ToList();

很快我就找到了答案:)

正如 Gert 在评论中所说,我必须传递一个变量,因此 EF 在那里发挥了一些作用。 因此,如果我将代码更改为此,则会发生:

var myId = 6;

var result = ctx.Posts
    .Include(x => x.PostType)
    .Where(x => x.PostTypeId == myId && x.CreationDate >= new DateTime(2013, 01, 01))
        .Select(x => new {
            Id = x.Id,
            Body = x.Body, 
            Type = x.PostType.Type
        }).ToList();

然后我得到 SQL 这样的

exec sp_executesql N'SELECT [p].[Id], [p].[Body], [p0].[Type]
FROM [Posts] AS [p]
INNER JOIN [PostTypes] AS [p0] ON [p].[PostTypeId] = [p0].[Id]
WHERE ([p].[PostTypeId] = @__myId_0) AND ([p].[CreationDate] >= ''2013-01-01T00:00:00.000'')',N'@__myId_0 int',@__myId_0=6

然后我可以用不同的值执行另一个

exec sp_executesql N'SELECT [p].[Id], [p].[Body], [p0].[Type]
FROM [Posts] AS [p]
INNER JOIN [PostTypes] AS [p0] ON [p].[PostTypeId] = [p0].[Id]
WHERE ([p].[PostTypeId] = @__myId_0) AND ([p].[CreationDate] >= ''2013-01-01T00:00:00.000'')',N'@__myId_0 int',@__myId_0=7

然后我可以在执行计划中看到使用了相同的查询计划,因为顶部的第一个查询设置了计划,然后第二个使用它并保留了估计的 166 行但实际上只有 4向后排

如果我查看第二个查询属性,我也可以确认这一点,并且可以看到它是用 6 编译的 put was 运行 with 7