【发布时间】:2010-09-30 04:10:31
【问题描述】:
我知道 WITH RECOMPILE 选项会强制优化器为存储过程重建查询计划,但您希望什么时候发生?
关于何时使用 WITH RECOMPILE 选项以及何时不使用,有哪些经验法则?
仅将其放在每个存储过程上的有效开销是多少?
【问题讨论】:
标签: sql sql-server options
我知道 WITH RECOMPILE 选项会强制优化器为存储过程重建查询计划,但您希望什么时候发生?
关于何时使用 WITH RECOMPILE 选项以及何时不使用,有哪些经验法则?
仅将其放在每个存储过程上的有效开销是多少?
【问题讨论】:
标签: sql sql-server options
最常见的用途是当您在过程中可能有一个动态 WHERE 子句时......您不希望该特定查询计划被编译并保存以供后续执行,因为它很可能不是完全相同的子句下次调用该过程时。
【讨论】:
只有在使用代表性数据和上下文进行测试时才应该使用它,证明不这样做会产生无效的查询计划(无论可能的原因是什么)。不要事先假设(未经测试)SP 不会正确优化。
仅手动调用的唯一例外(即不要将其编码到 SP 中):当您知道您已大幅更改目标表的字符时。例如TRUNCATE、批量加载等。
这是另一个过早优化的机会。
注意:我有很多积分。如果新手在下面提交了相同的答案,并且您同意,请为他们的答案投票。
【讨论】:
将它放在每个存储过程上并不是一个好主意,因为编译查询计划是一项相对昂贵的操作,而且您不会看到缓存和重用查询计划的任何好处。
可以使用sp_executesql 来处理在存储过程中构建的动态where 子句的情况来执行TSQL,而不是在存储过程中添加WITH RECOMPILE。
另一个解决方案(SQL Server 2005 及更高版本)是使用带有特定参数的提示,使用 OPTIMIZE FOR 提示。如果行中的值是静态的,这将很有效。
SQL Server 2008 引入了一个名为“OPTIMIZE FOR UNKNOWN”的little known feature:
此提示指导查询优化器 使用它拥有的标准算法 如果没有参数值,则始终使用 完全被传递给查询。 在这种情况下,优化器将看起来 在所有可用的统计数据中 确定什么是 用于局部变量的值 生成查询计划应该是, 而不是看具体的 传递给的参数值 应用程序的查询。
【讨论】:
正如其他人所说,您不想在每个存储过程中简单地包含WITH RECOMPILE 作为习惯问题。通过这样做,您将消除存储过程的主要好处之一:它保存了查询计划这一事实。
为什么这可能很重要?计算查询计划比编译常规过程代码要密集得多。因为 SQL 语句的语法只指定 what 你想要的,而不是(通常)如何 得到它,这使得数据库在创建物理计划(即实际收集和修改数据的分步说明)。数据库查询预处理器可以做很多“技巧”以及它可以做出的选择——连接表的顺序、要使用的索引、是否在连接之前或之后应用 WHERE 子句等。
对于一个简单的 SELECT 语句,它可能没有什么不同,但对于任何重要的查询,数据库将花费一些时间(以毫秒为单位,而不是通常的微秒)来提出一个最优方案。对于真正复杂的查询,它甚至不能保证一个最优计划,它只能使用启发式方法来提出一个相当好的计划。因此,通过强制它每次重新编译,你是在告诉它它必须一遍又一遍地经历这个过程,即使它之前得到的计划非常好。
根据供应商的不同,应该有用于重新编译查询计划的自动触发器 - 例如,如果表上的统计信息发生显着变化(例如,某个列中值的直方图开始随着时间的推移均匀分布变得高度倾斜),那么数据库应该注意到并重新编译计划。但一般来说,数据库的实现者总体上会比你更聪明。
与任何与性能相关的事情一样,不要在黑暗中拍摄;找出消耗 90% 性能的瓶颈在哪里,然后首先解决它们。
【讨论】:
通常WITH RECOMPILE 的更好替代方案是OPTION(RECOMPILE)
正如您在下面的解释中看到的,取自the answer of this question here
当遇到参数敏感问题时,常见的一块 论坛和问答网站上的建议是“使用重新编译”(假设 前面介绍的其他调整选项不合适)。很遗憾, 该建议经常被误解为意味着添加 WITH RECOMPILE 存储过程的选项。
使用 WITH RECOMPILE 可以有效地将我们返回到 SQL Server 2000 行为,其中整个存储过程在每次重新编译 执行。在 SQL Server 2005 及更高版本上,更好的选择是 仅对以下语句使用 OPTION (RECOMPILE) 查询提示 受到参数嗅探问题的困扰。此查询提示结果 仅在重新编译有问题的陈述时;执行计划 for 存储过程中的其他语句被缓存和重用 像平常一样。
使用 WITH RECOMPILE 也意味着存储的编译计划 过程没有被缓存。因此,没有性能信息 在 DMV 中维护,例如 sys.dm_exec_query_stats。使用查询 提示相反意味着可以缓存已编译的计划,并且性能 信息可在 DMV 中获得(但仅限于最 最近执行,仅适用于受影响的语句)。
对于至少运行 SQL Server 2008 build 2746(服务 Pack 1 with Cumulative Update 5),使用 OPTION (RECOMPILE) 有另一个 与 WITH RECOMPILE 相比的显着优势:只有 OPTION(重新编译) 启用参数嵌入优化。
【讨论】: