有什么提示可以确保在运行特定查询时优化器不会使用缓存的查询计划吗?
我已经找到了强制使用特定计划的 MSDN页面 -但我需要相反的规定。我尝试添加以下提示:
OPTION (USE NO PLAN);
还是实际上需要清除缓存的一部分?
对于单个查询,您可以使用OPTION RECOMPILE 查询提示在每次执行时强制执行新计划。就像这样:
OPTION RECOMPILE
SELECT T.Column1, T2.Column2 FROM T INNER JOIN T2 ON T.ID = T2.ID WHERE T.Column2 = @SomeParameter OPTION (RECOMPILE);
或在存储过程级别上,可以使用WITH RECOMPILE:
CREATE PROCEDURE dbo.TestRecompile @Param INT WITH RECOMPILE AS SELECT * FROM dbo.T;
如果一次性要从重新编译中标记存储过程(即下次运行时不使用缓存的计划),则可以使用SP_RECOMPILE:
EXECUTE sp_recompile 'dbo.ProcedureName';
我不知道马丁·史密斯(Martin Smith)提到的复杂性,我试图重新创建它们,但是无法(尽管我第二次不怀疑他,我只是认为我的测试场景太简单了),但是,我想我会无论如何添加结果。
我创建了以下架构:
IF OBJECT_ID(N'dbo.T', 'U') IS NOT NULL DROP TABLE dbo.T; GO CREATE TABLE dbo.T ( ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, Column1 INT NOT NULL, Column2 INT NULL ); INSERT dbo.T (Column1, Column2) SELECT TOP 9999 1, Number FROM Master..spt_values UNION ALL SELECT TOP 1001 Number, Number FROM Master..spt_values WHERE Type ='P'; CREATE NONCLUSTERED INDEX IX_T_Column1 ON dbo.T (Column1 ASC);
故意对表进行加权,以便选择在何处column1 = 1应使用聚集索引扫描,但所有其他条件都应使用非聚集索引。控制案例是:
column1 = 1
DBCC FREEPROCCACHE; DECLARE @SQL NVARCHAR(MAX) = 'SELECT COUNT(T.Column2) FROM dbo.T WHERE T.Column1 = @ID'; DECLARE @ParamDef NVARCHAR(MAX) = N'@ID INT'; EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 1; EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 2;
这产生了两个相同的计划:
下一个场景是添加OPTION (RECOMPILE)到查询中:
OPTION (RECOMPILE)
DBCC FREEPROCCACHE; DECLARE @SQL NVARCHAR(MAX) = ' SELECT COUNT(T.Column2) FROM dbo.T WHERE T.Column1 = @ID OPTION (RECOMPILE);'; DECLARE @ParamDef NVARCHAR(MAX) = N'@ID INT'; EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 1; EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 2;
这为@ID = 1提供了与前两个执行计划相同的执行计划,但是现在对@ID = 2使用书签查找,这是检索单行时更有效的计划。
注意:如果我先执行@ID = 2而没有重新编译,则两个计划都将相同,但是两个都将使用上面显示的用于@ID = 2的键查找
另一种选择OPTION (RECOMPILE)是清除特定查询的缓存:
DBCC FREEPROCCACHE; DECLARE @SQL NVARCHAR(MAX) = ' SELECT COUNT(T.Column2) FROM dbo.T WHERE T.Column1 = @ID'; DECLARE @ParamDef NVARCHAR(MAX) = N'@ID INT'; EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 1; EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 2; DECLARE @PlanHandle VARBINARY(64) = ( SELECT TOP 1 PLAN_HANDLE FROM SYS.DM_EXEC_CACHED_PLANS CROSS APPLY SYS.DM_EXEC_SQL_TEXT(PLAN_HANDLE) AS ST WHERE ST.TEXT = '(' + @ParamDef + ')' + @SQL ); DBCC FREEPROCCACHE (@PlanHandle); EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 2;
最初(与控制案例类似),所有参数值都使用相同的计划,但是,可以清除特定查询定义的缓存,完成后,键查找计划将用于@ID = 2;
因此,如果OPTION (RECOMPILE)未按预期工作,则可以使用查询文本的计划句柄来清除该特定查询的缓存。