【发布时间】:2018-09-01 21:57:49
【问题描述】:
请参阅下面的查询。为了不泄露机密/敏感信息,对象和属性名称经过了一定程度的混淆,但查询结构是相同的。
当添加.OrderBy(p => "") 时,这对我来说完全是无意义的,查询运行得更快。执行查询所需的时间从大约。 2000ms 下降到大约。 400 毫秒。我已经测试了几次,只添加和删除了 OrderBy 语句。
我完全不解,这怎么可能?查询在 Azure 环境中的 SQL 数据库上执行。
我可以理解,在属性 A 上排序数据,然后选择属性 A 等于某个值的记录可能会加快查询速度。但是在一个空字符串上排序!?这是怎么回事?
我还想指出,没有 OrderBy 的查询使用表达式(如 suggested in this post to circumvent SQL parameter sniffing)将执行时间也降低到大约。 400 毫秒。然后添加 .OrderBy(p => "") 不会产生任何明显的差异。
var query = (from p in Context.Punders.Where(p => p.A == A)
.Where(p => null != p.SomeNumber)
.Where(p => p.StatusCode == Default ||
p.StatusCode == Cancelled)
.Where(p => p.DatePosted >= startDate && p.DatePosted <= endDate)
join f in Context.Founders.Where(f => f.A == A) on p.Code equals f.Code
join r in Context.Rounders.Where(r => r.A == A) on p.Code equals r.Code
into rg
from r in rg.DefaultIfEmpty()
join pt in Context.FishTypes.Where(ft => ft.A ==A) on p.Code equals pt.Code
where r == null
select new
{
p.Code,
f.B,
f.C,
p.D,
p.E,
pt.F,
pt.G,
p.H
})
.OrderBy(p => "");
不带.OrderBy(...的查询
SELECT [Filter1].[q] AS [q],
[Filter1].[c1] AS [edoc],
[Filter1].[oc1] AS [wnrdc],
[Filter1].[otc1] AS [weener],
[Filter1].[ptc1] AS [pmtpdc],
[Extent4].[isr] AS [isr],
[Extent4].[rac] AS [rac],
[Filter1].[arn] AS [arn]
FROM (SELECT [Extent1].[pcid] AS [pcid1],
[Extent1].[edoc] AS [c1],
[Extent1].[pmtpdc] AS [ptc1],
[Extent1].[q] AS [q],
[Extent1].[arn] AS [arn],
[Extent1].[dateposted] AS [DatePosted],
[Extent2].[pcid] AS [pcid2],
[Extent2].[wnrdc] AS [oc1],
[Extent2].[weener] AS [otc1]
FROM [fnish].[post] AS [Extent1]
INNER JOIN [fnish].[olik] AS [Extent2]
ON [Extent1].[olikedoc] = [Extent2].[edoc]
LEFT OUTER JOIN [fnish].[receivable] AS [Extent3]
ON ( [Extent3].[pcid] = @p__linq__4 )
AND ( [Extent1].[edoc] =
[Extent3].[pepstedoc] )
WHERE ( [Extent1].[arn] IS NOT NULL )
AND ( [Extent1].[posttedoc] IN ( N'D', N'X' ) )
AND ( [Extent3].[id] IS NULL )) AS [Filter1]
INNER JOIN [fnish].[paymenttype] AS [Extent4]
ON [Filter1].[ptc1] = [Extent4].[edoc]
WHERE ( [Filter1].[pcid1] = @p__linq__0 )
AND ( [Filter1].[dateposted] >= @p__linq__1 )
AND ( [Filter1].[dateposted] <= @p__linq__2 )
AND ( [Filter1].[pcid2] = @p__linq__3 )
AND ( [Extent4].[pcid] = @p__linq__5 )
使用.OrderBy(...查询
SELECT [Project1].[q] AS [q],
[Project1].[edoc] AS [edoc],
[Project1].[wnrdc] AS [wnrdc],
[Project1].[weener] AS [weener],
[Project1].[pmtpdc] AS [pmtpdc],
[Project1].[isr] AS [isr],
[Project1].[rac] AS [rac],
[Project1].[arn] AS [arn]
FROM (SELECT N'' AS [C1],
[Filter1].[c1] AS [edoc],
[Filter1].[ptc1] AS [pmtpdc],
[Filter1].[q] AS [q],
[Filter1].[arn] AS [arn],
[Filter1].[oc1] AS [wnrdc],
[Filter1].[otc1] AS [weener],
[Extent4].[isr] AS [isr],
[Extent4].[rac] AS [rac]
FROM (SELECT [Extent1].[pcid] AS [pcid1],
[Extent1].[edoc] AS [c1],
[Extent1].[pmtpdc] AS [ptc1],
[Extent1].[q] AS [q],
[Extent1].[arn] AS [arn],
[Extent1].[dateposted] AS [DatePosted],
[Extent2].[pcid] AS [pcid2],
[Extent2].[wnrdc] AS [oc1],
[Extent2].[weener] AS [otc1]
FROM [fnish].[post] AS [Extent1]
INNER JOIN [fnish].[olik] AS [Extent2]
ON [Extent1].[olikedoc] = [Extent2].[edoc]
LEFT OUTER JOIN [fnish].[receivable] AS [Extent3]
ON ( [Extent3].[pcid] =
@p__linq__4 )
AND ( [Extent1].[edoc] =
[Extent3].[pepstedoc] )
WHERE ( [Extent1].[arn] IS NOT NULL )
AND ( [Extent1].[posttedoc] IN ( N'D', N'X' ) )
AND ( [Extent3].[id] IS NULL )) AS [Filter1]
INNER JOIN [fnish].[paymenttype] AS [Extent4]
ON [Filter1].[ptc1] = [Extent4].[edoc]
WHERE ( [Filter1].[pcid1] = @p__linq__0 )
AND ( [Filter1].[dateposted] >= @p__linq__1 )
AND ( [Filter1].[dateposted] <= @p__linq__2 )
AND ( [Filter1].[pcid2] = @p__linq__3 )
AND ( [Extent4].[pcid] = @p__linq__5 )) AS [Project1]
ORDER BY [Project1].[c1] ASC
结论
据我所知,有一点猜测:这是特定于案例的行为。在我的例子中,性能提升可能是由于 SQL 服务器正在构建不同的执行计划,从而产生更好的查询。我已经看到了一个不同的执行计划,其中没有OrderBy 的查询使用SQL 语句OPTION(RECOMIPILE) 显示出类似的性能提升。因此,将OrderBy 添加到 LINQ 查询很可能(我认为)产生不同的执行计划,从而产生更好的查询。
【问题讨论】:
-
运行 SQL 分析器并检查 EF 生成的 sql 查询
-
你可以试试 LINQPad。这是一个很棒的工具。你把 linq 写成 sql 或者 ef 就可以立即看到生成的 sql。 (我不隶属,只是一个用户)。这样,您可以看到添加 order by 子句时 SQL 的变化情况。
-
鉴于您的注释,我认为 sql server 为您的查询缓存了计划,并且对于给定的值,该计划无效。通过添加订单,您可以强制它创建新的执行计划(因为它现在是不同的查询)。
-
请用两条 SQL 语句更新您的问题。此外,如果您清除计划缓存会发生什么? stackoverflow.com/questions/8495210/resetting-execution-plans
-
@mjwills 感谢您的提醒。我将它们添加到帖子中。我看到使用
OrderBy生成的查询的第三个子查询,所以现在我很清楚性能提升可能是由于不同的执行计划。由于 SQLOPTION(RECOMPILE)在通过 SQL Management Studio 运行“原始”SQL 查询时显示出类似的性能提升。
标签: c# sql-server performance linq-to-entities azure-sql-database