J. *_*ini 0 stored-procedures t-sql execution-plan recompile sql-server-2019
我最近读完 《SQL Server 2008 中的计划缓存》 ,我感到很困惑。看起来,除了完全刷新计划缓存或明确要求重新编译存储过程之外,从 SQL Server 2008 开始,存储过程的重新编译都是在语句级别而不是存储过程级别完成的。
那么,除了显式刷新缓存或要求重新编译(例如WITH RECOMPILE
)之外,什么可以在 SQL Server 2019 中重新编译完整的存储过程,而不仅仅是重新编译单个语句呢?
举一个我感到困惑的例子,请考虑以下过程。
CREATE PROCEDURE FOO AS
BEGIN
SELECT * INTO #temp1 FROM table1
INSERT BAR1 SELECT * FROM #temp1
INSERT BAR2 SELECT * FROM #temp1
END
Run Code Online (Sandbox Code Playgroud)
我可以想到很多可能导致SELECT * INTO #temp1 FROM table1
重新编译的事情,但是如果没有下一行也重新编译,那么重新编译会很奇怪。这让我觉得 SQL Server 中一定有一些东西会导致整个存储过程重新编译。
除了您的问题中列出的内容之外,存储过程确实没有常见的通用原因总是为每个语句重新编译新计划,至少对于您的示例中的语句来说是这样。
\nSQL Server 提供了几种不同的方法来跟踪重新编译,但它们都是语句级的。也许最容易获得答案的是扩展事件。我遇到过在对象级别没有跟踪重新编译的事件。
\nSELECT\n d.map_value\nFROM sys.dm_xe_map_values AS d\nWHERE d.name = \'statement_recompile_cause\'\nORDER BY\n d.map_key;\n
Run Code Online (Sandbox Code Playgroud)\n截至 SQL Server 2022,这列出了 23 个重新编译的原因,其中包括“不是重新编译”。
\n我知道有几件事会阻止计划缓存,这会使模块看起来每次都需要重新编译(尽管实际上我觉得这更像是每次都进行编译)。
\n正如保罗在他的帖子中指出的那样:
\n\n\n第二个选项是包含一条将整个批次标记为不可缓存的语句。合适的语句通常与安全相关,或者以某种方式敏感。
\n这可能听起来不切实际,但有一些缓解措施。\n首先,不需要执行敏感语句\xe2\x80\x94,它只需要\n存在即可。当满足该条件时,运行批处理的用户\n\n\xe2\x80\x99t甚至需要执行敏感语句的权限。请注意,效果仅限于包含敏感语句的批处理。
\n
请点击链接查看几个示例。
\n我还没有发表过关于此的文章,但总体思路是,当存在未经探索的情况时IF
存储过程中存在未探索的分支引用不存在的对象时,整个批次是不可缓存的。
请随意跟随下面的演示。请注意,如果您尝试获取如下所示的存储过程的估计计划,或者如果您以探索具有不存在对象的分支的方式运行它,它将引发错误。
\n/*Create a table if you need to*/\nCREATE TABLE \n dbo.DinnerPlans\n(\n id bigint IDENTITY,\n name nvarchar(40) NOT NULL,\n seat_number tinyint NULL,\n is_free bit NOT NULL,\n);\nGO\n\n/*First example, with an object that doesn\'t exist*/\nCREATE OR ALTER PROCEDURE\n dbo.i_live\n(\n @decider bit = NULL\n)\nAS\nBEGIN\n SET NOCOUNT, XACT_ABORT ON;\n \n IF @decider = \'true\'\n BEGIN\n SELECT\n dp.*\n FROM dbo.DinnerPlans AS dp;\n END;\n \n IF @decider = \'false\'\n BEGIN\n SELECT\n whatever.*\n FROM dbo.AnObjectThatDoesntEvenPretendToExist AS whatever;\n END;\n \n IF @decider IS NULL\n BEGIN\n SELECT\n result = \n \'please make a decision.\'\n END;\nEND;\nGO \n\n/*Say goodbye!*/\nDBCC FREEPROCCACHE;\n\n/*This runs without an error*/\nEXEC dbo.i_live \n @decider = \'true\';\n\n/*But there\'s no query plan!*/\nSELECT\n object_name =\n OBJECT_NAME(deps.object_id, deps.database_id), \n deps.type_desc,\n deps.last_execution_time,\n deps.execution_count,\n dest.text,\n query_plan =\n TRY_CAST(detqp.query_plan AS xml)\nFROM sys.dm_exec_procedure_stats AS deps\nOUTER APPLY sys.dm_exec_sql_text(deps.plan_handle) AS dest\nOUTER APPLY sys.dm_exec_text_query_plan(deps.plan_handle, 0, -1) AS detqp;\nGO \n
Run Code Online (Sandbox Code Playgroud)\n