当从参数化查询更改为非参数化查询时,我无法理解 SQL Server 中我的语句的估计查询计划的行为。
我有以下查询:
DECLARE @p0 UniqueIdentifier = '1fc66e37-6eaf-4032-b374-e7b60fbd25ea'
SELECT [t5].[value2] AS [Date], [t5].[value] AS [New]
FROM (
SELECT COUNT(*) AS [value], [t4].[value] AS [value2]
FROM (
SELECT CONVERT(DATE, [t3].[ServerTime]) AS [value]
FROM (
SELECT [t0].[CookieID]
FROM [dbo].[Usage] AS [t0]
WHERE ([t0].[CookieID] IS NOT NULL) AND ([t0].[ProductID] = @p0)
GROUP BY [t0].[CookieID]
) AS [t1]
OUTER APPLY (
SELECT TOP (1) [t2].[ServerTime]
FROM [dbo].[Usage] AS [t2]
WHERE ((([t1].[CookieID] IS NULL) AND ([t2].[CookieID] IS NULL))
OR (([t1].[CookieID] IS NOT NULL) AND ([t2].[CookieID] IS NOT NULL)
AND ([t1].[CookieID] = [t2].[CookieID])))
AND ([t2].[CookieID] IS NOT NULL)
AND ([t2].[ProductID] = @p0)
ORDER BY [t2].[ServerTime]
) AS [t3]
) AS [t4]
GROUP BY [t4].[value]
) AS [t5]
ORDER BY [t5].[value2]
此查询由 Linq2SQL 表达式生成并从 LINQPad 中提取。这会产生一个很好的查询计划(据我所知)并在大约 10 秒内在数据库上执行。但是,如果我用精确值替换参数的两种用途,即用 '= '1fc66e37-6eaf-4032-b374-e7b60fbd25ea' ' 替换两个 '= @p0' 部分,我会得到一个不同的估计查询计划和查询现在运行时间更长(超过 60 秒,还没有看透)。
为什么执行看似无辜的替换会产生效率低得多的查询计划和执行?我已经使用“DBCC FreeProcCache”清除了过程缓存,以确保我没有缓存错误的计划,但行为仍然存在。
我真正的问题是我可以忍受 10 秒的执行时间(至少在很长一段时间内),但我不能忍受 60 多秒的执行时间。我的查询将(如上所述)由 Linq2SQL 生成,因此它在数据库上执行为
exec sp_executesql N'
...
WHERE ([t0].[CookieID] IS NOT NULL) AND ([t0].[ProductID] = @p0)
...
AND ([t2].[ProductID] = @p0)
...
',N'@p0 uniqueidentifier',@p0='1FC66E37-6EAF-4032-B374-E7B60FBD25EA'
这会产生同样糟糕的执行时间(我认为这很奇怪,因为这似乎是在使用参数化查询。
我不是在寻找关于创建哪些索引等的建议,我只是想了解为什么查询计划和执行在三个看似相似的查询上如此不同。
编辑:我已经上传了非参数化和参数化查询的执行计划,以及带有不同 GUID的参数化查询的执行计划(如Heinz建议的) here
希望它可以帮助你帮助我:)