在为引用名为“#test”的临时表的存储过程中的一段 SQL 验证计划指南时,函数 fn_validate_plan_guide 返回错误:对象名称“#test”无效。
但是计划指南仍然将查询提示推送到 SQL 中,并实现了所需的执行。
这是否突出了 fn_validate_plan_guide 函数的问题?
下面的脚本重现了这个问题。
--Enable the actual execution plan before running the query so the plans can be compared
USE [msdb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[test]
AS
BEGIN
CREATE TABLE #test
(
ID INT
)
INSERT INTO #test
SELECT ROW_NUMBER() OVER(ORDER BY job_id)
FROM dbo.sysjobs
SELECT *
FROM #test t
JOIN #test t2 ON t.ID = t2.ID
DROP TABLE #Test
END
GO
--Execution before the plan guide is created will have a hash join in the second batch
EXEC msdb.dbo.test
GO
--Create the plan guide
EXEC sp_create_plan_guide 'test',
' SELECT *
FROM #test t
JOIN #test t2 ON t.ID = t2.ID',
'OBJECT', 'dbo.test', NULL, 'OPTION (MERGE JOIN)'
GO
--Validate the plan guide. This returns the error "Invalid object name '#test'."
SELECT
plan_guide_id, msgnum, severity, state, message,
name, create_date, is_disabled, query_text, scope_type_desc, scope_batch, parameters, hints
FROM sys.plan_guides
CROSS APPLY fn_validate_plan_guide(plan_guide_id);
GO
--Execution after the plan guide is created will have a merge join in the second batch
EXEC msdb.dbo.test
GO
EXEC sp_control_plan_guide 'DISABLE', 'test'
GO
--Execution after the plan guide is disabled will go back to having a hash join in the second batch
EXEC msdb.dbo.test
GO
EXEC sp_control_plan_guide 'ENABLE', 'test'
GO
--Execution after the plan guide is re-enabled will go back to having a merge join in the second batch
EXEC msdb.dbo.test
GO
--Clean up
EXEC sp_control_plan_guide 'DROP', 'test'
GO
DROP PROCEDURE test
GO
这个函数给出的错误是误报,还是这些只是计划指南可能失败的警告,还是我没有想到的其他事情?
我在这里用上面的文字创建了一个连接项目,但我还没有收到回复。
是的,这是sys.fn_validate_plan_guide的限制,可能会导致误报(不是误报)。
服务器尝试只编译计划指南中的语句,而不是整个批处理(在本例中为存储过程)。请求失败,因为临时表定义不是编译的一部分。
我无法用表变量重现相同的问题:
计划验证和指南应用程序工作正常。
解决方法
请求调用过程的估计计划成功,生成的批处理计划显示指导计划,语句根节点的属性在 SSMS 中显示正确的PlanGuideDB和PlanGuideName属性:
另一种方法是在调用sys.fn_validate_plan_guide的会话上创建临时表(从过程定义中复制) 。
当错误指的是缺少#object 时,其中任何一个都可用于验证 sys.fn_validate_plan_guide 的否定结果。