【问题标题】:Rule of thumb on when to use WITH RECOMPILE option关于何时使用 WITH RECOMPILE 选项的经验法则
【发布时间】:2010-09-30 04:10:31
【问题描述】:

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

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

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

【问题讨论】:

    标签: sql sql-server options


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • @le dorfier:我不同意。只有在没有其他可用选项时才应使用它。我当然不建议在测试期间使用它,因为您的测试数据可能无法代表生产环境。
      • 然后我不清楚,我们同意。我的意思是,如果测试反复显示对代表性数据的异常优化,那么您可能需要构建它(然后直到您弄清楚是什么弄乱了异常)。现在有一个问题在起作用。
      【解决方案3】:

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

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

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

      SQL Server 2008 引入了一个名为“OPTIMIZE FOR UNKNOWN”的little known feature

      此提示指导查询优化器 使用它拥有的标准算法 如果没有参数值,则始终使用 完全被传递给查询。 在这种情况下,优化器将看起来 在所有可用的统计数据中 确定什么是 用于局部变量的值 生成查询计划应该是, 而不是看具体的 传递给的参数值 应用程序的查询。

      【讨论】:

      • 关于优化未知的好信息。但是,我会将所有提示与 WITH RECOMPILE 归为同一类别。对我来说,这一直意味着我有一个错误的查询,我需要重构,直到我不需要任何一个。
      • @dorfier:提示有用,是的,只有在绝对需要时才应该使用它们。我见过写得很好但遭受“参数嗅探”的查询,导致错误的查询计划被缓存。这是因为有大量可选参数采用广泛的值
      • @mitch:这对我来说通常意味着我应该屈从于查询字符串连接。但我讨厌那些。当然,通常这是报告要求。那时我希望有一个好的 QBE 工具。
      【解决方案4】:

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

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

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

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

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

      【讨论】:

      • 谢谢伊恩。我没有使用 WITH RECOMPILE。它在我上一份工作的标准 sproc 模板中(!?),但从来不知道为什么。我最近花了更多时间做一些优化,我真的只是想看看这个选项的底层。感谢您提供所有详细信息!
      • 非常有帮助。谢谢!
      • 我不会称之为“非常好”。如果查询在存储过程中并带有参数,则 sql server 将使用参数嗅探,这可能会导致缓存“错误”执行计划(如果您没有禁用参数嗅探..)
      【解决方案5】:

      通常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(重新编译) 启用参数嵌入优化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-03
        • 2020-09-12
        • 2014-01-09
        • 2016-12-13
        • 1970-01-01
        • 2010-10-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多