SQL Server查询计划的差异

sor*_*rke 6 sql-server parameterized sql-execution-plan

当从参数化查询更改为非参数化查询时,我无法理解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]
Run Code Online (Sandbox Code Playgroud)

此查询由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'
Run Code Online (Sandbox Code Playgroud)

这会产生相同的糟糕执行时间(我认为这更加奇怪,因为这似乎是使用参数化查询.

我不是在寻找关于要创建哪些索引等的建议,我只是想了解为什么查询计划和执行在三个看似相似的查询上如此不同.

编辑:我已上载的执行计划的非参数和参数化查询以及用于参数化查询执行计划(如建议亨氏)具有不同的GUID 这里

希望它可以帮助你帮助我:)

Qua*_*noi 2

我并不是在寻求有关创建哪些索引等的建议,我只是想了解为什么三个看似相似的查询的查询计划和执行如此不同。

您似乎有两个索引:

IX_NonCluster_Config (ProductID, ServerTime)
IX_NonCluster_ProductID_CookieID_With_ServerTime (ProductID, CookieID) INCLUDE (ServerTime)
Run Code Online (Sandbox Code Playgroud)

第一个索引不覆盖,CookieID但按顺序排列,因此对于选择性较低的索引(即您有很多索引的索引)ServerTime来说更有效ProductID

第二个索引确实覆盖了所有列,但没有排序,因此对于更具选择性的ProductID列(那些很少的列)来说更有效。

平均而言,您的ProductID基数期望SQL Server第二种方法高效,这就是您使用参数化查询或显式提供选择时使用的方法GUID

然而,您的原始版本GUID被认为选择性较低,这就是使用第一种方法的原因。

不幸的是,第一种方法需要额外的过滤,CookieID这就是它实际上效率较低的原因。