我们有一个带有 150-200 个存储过程的 SQL Server DB,除了一个之外,所有这些都在 sys.dm_exec_query_plan 中生成一个可查看的查询计划。根据http://msdn.microsoft.com/en-us/library/ms189747.aspx:
在以下情况下,sys.dm_exec_query_plan 的返回表的 query_plan 列中没有返回 Showplan 输出:
- 如果使用plan_handle 指定的查询计划已从计划缓存中逐出,则返回表的query_plan 列为空。例如,如果在捕获计划句柄和将其与 sys.dm_exec_query_plan 一起使用之间存在时间延迟,则可能会出现这种情况。
- 某些 Transact-SQL 语句未缓存,例如批量操作语句或包含大小超过 8 KB 的字符串文字的语句。无法使用 sys.dm_exec_query_plan 检索此类语句的 XML 显示计划,除非批处理当前正在执行,因为它们不存在于缓存中。
- 如果 Transact-SQL 批处理或存储过程包含对用户定义函数的调用或对动态 SQL 的调用,例如使用 EXEC(字符串),则为用户定义函数编译的 XML Showplan 不包含在返回的表中通过 sys.dm_exec_query_plan 用于批处理或存储过程。相反,您必须为与用户定义函数对应的计划句柄单独调用 sys.dm_exec_query_plan。
然后..
由于 xml 数据类型中允许的嵌套级别数的限制,sys.dm_exec_query_plan 无法返回满足或超过 128 级嵌套元素的查询计划。
我相信这些都不适用于这个程序。结果永远不会有查询计划,无论时间如何,因此 1 不适用。没有长字符串文字或批量操作,因此 2 不适用。没有用户定义的函数或动态 SQL,因此 3 不适用。而且几乎没有嵌套,所以最后一个不适用。事实上,这是一个非常简单的过程,我将其全部包含在内(更改了一些表名以保护无辜者)。请注意,参数嗅探的恶作剧是在问题发生后出现的。即使我直接在查询中使用参数,它仍然会发生。关于为什么我没有此过程的可见查询计划的任何想法?
ALTER PROCEDURE [dbo].[spGetThreadComments]
@threadId int,
@stateCutoff int = 80,
@origin varchar(255) = null,
@includeComments bit = 1,
@count int = 100000
AS
if (@count is null)
begin
select @count = 100000
end
-- copy parameters to local variables to avoid parameter sniffing
declare @threadIdL int, @stateCutoffL int, @originL varchar(255), @includeCommentsL bit, @countL int
select @threadIdL = @threadId, @stateCutoffL = @stateCutoff, @originL = @origin, @includeCommentsL = @includeComments, @countL = @count
set rowcount @countL
if (@originL = 'Foo')
begin
select * from FooComments (nolock) where threadId = @threadId and statusCode <= @stateCutoff
order by isnull(parentCommentId, commentId), dateCreated
end
else
begin
if (@includeCommentsL = 1)
begin
select * from Comments (nolock)
where threadId = @threadIdL and statusCode <= @stateCutoffL
order by isnull(parentCommentId, commentId), dateCreated
end
else
begin
select userId, commentId from Comments (nolock)
where threadId = @threadIdL and statusCode <= @stateCutoffL
order by isnull(parentCommentId, commentId), dateCreated
end
end