15

我知道 WITH RECOMPILE 选项会强制优化器为存储过程重建查询计划,但是您希望什么时候发生呢?

关于何时使用 WITH RECOMPILE 选项以及何时不使用,有哪些经验法则?

将它放在每个存储过程上的有效开销是多少?

4

5 回答 5

17

正如其他人所说,您不想简单地包含WITH RECOMPILE在每个存储过程中作为习惯问题。通过这样做,您将消除存储过程的主要好处之一:它保存了查询计划这一事实。

为什么这可能是一件大事?计算查询计划比编译常规过程代码要密集得多。因为 SQL 语句的语法只指定您想要的内容,而不是(通常)如何获取它,这使得数据库在创建物理计划时具有很大程度的灵活性(即逐步说明实际收集和修改数据)。数据库查询预处理器可以做很多“技巧”以及它可以做出的选择——连接表的顺序、要使用的索引、是否WHERE在连接之前或之后应用子句等。

对于一个简单的 SELECT 语句,它可能没有什么不同,但对于任何不平凡的查询,数据库将花费一些时间(以毫秒为单位,而不是通常的微秒)来提出最佳计划。对于非常复杂的查询,它甚至不能保证一个最优的计划,它只能使用启发式来提出一个很好的计划。因此,通过强制它每次重新编译,你是在告诉它它必须一遍又一遍地经历这个过程,即使它之前得到的计划非常好。

根据供应商的不同,应该有用于重新编译查询计划的自动触发器 - 例如,如果表上的统计信息发生显着变化(例如,某个列中值的直方图开始随着时间的推移均匀分布变得高度倾斜),那么数据库应该注意到并重新编译计划。但一般来说,数据库的实现者总体上会比你更聪明。

与任何与性能相关的事情一样,不要在黑暗中拍摄;找出消耗 90% 性能的瓶颈在哪里,并首先解决它们。

于 2009-01-07T23:58:27.713 回答
14

将它放在每个存储过程上并不是一个好主意,因为编译查询计划是一项相对昂贵的操作,而且您不会从缓存和重用查询计划中看到任何好处。

在存储过程中构建的动态 where 子句的情况可以通过sp_executesql执行 TSQL 来处理,而不是添加WITH RECOMPILE到存储过程中。

另一种解决方案(SQL Server 2005 及更高版本)是使用带有特定参数的提示使用OPTIMIZE FOR提示。如果行中的值是静态的,这很有效。

SQL Server 2008 引入了一个鲜为人知的特性,叫做“ OPTIMIZE FOR UNKNOWN”:

如果根本没有将参数值传递给查询,则此提示指示查询优化器使用它一直使用的标准算法。在这种情况下,优化器将查看所有可用的统计数据来确定用于生成查询计划的局部变量的值应该是什么,而不是查看应用程序传递给查询的特定参数值。

于 2009-01-07T23:51:15.260 回答
2

最常见的用途是当您在过程中可能有一个动态 WHERE 子句时......您不希望该特定查询计划被编译并保存以供后续执行,因为下次它很可能不是完全相同的子句该过程被调用。

于 2009-01-07T23:40:23.160 回答
2

通常一个更好的选择WITH RECOMPILEOPTION(RECOMPILE) 你可以在下面的解释中看到,取自这个问题的答案here

当遇到参数敏感问题时,论坛和问答网站上的一条常见建议是“使用重新编译”(假设前面介绍的其他调整选项不合适)。不幸的是,该建议经常被误解为向存储过程添加 WITH RECOMPILE 选项。

使用 WITH RECOMPILE 可以有效地将我们返回到 SQL Server 2000 行为,其中整个存储过程在每次执行时都会重新编译。在 SQL Server 2005 及更高版本上,更好的替代方法是仅对遭受参数嗅探问题的语句使用 OPTION (RECOMPILE) 查询提示。此查询提示仅导致重新编译有问题的语句;存储过程中其他语句的执行计划被缓存并照常重用。

使用 WITH RECOMPILE 还意味着存储过程的编译计划不会被缓存。因此,在 sys.dm_exec_query_stats 等 DMV 中不会维护任何性能信息。相反,使用查询提示意味着可以缓存已编译的计划,并且 DMV 中提供了性能信息(尽管它仅限于最近的执行,仅限受影响的语句)。

对于至少运行 SQL Server 2008 build 2746(带有累积更新 5 的 Service Pack 1)的实例,使用 OPTION (RECOMPILE) 与 WITH RECOMPILE 相比具有另一个显着优势:只有 OPTION (RECOMPILE) 启用参数嵌入优化。

于 2016-10-20T11:43:42.033 回答
1

只有在使用代表性数据和上下文进行测试时才应该使用它,证明不这样做会产生无效的查询计划(无论可能的原因是什么)。不要事先假设(未经测试)SP 不会正确优化。

仅手动调用的唯一例外(即不要将其编码到 SP 中):当您知道您已经大幅更改了目标表的特征时。例如 TRUNCATE、批量加载等。

这是过早优化的又一个机会。

注意:我有很多积分。如果新手在下面提交了相同的答案,并且您同意,请为他们的答案投票。

于 2009-01-07T23:46:28.780 回答