首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >选项(重新编译)总是更快;为什么?

选项(重新编译)总是更快;为什么?
EN

Stack Overflow用户
提问于 2014-01-01 09:59:29
回答 6查看 245K关注 0票数 200

我遇到了一种奇怪的情况,将OPTION (RECOMPILE)附加到我的查询后,它会在半秒内运行,而忽略它会导致查询花费5分钟以上的时间。

当从query Analyzer或通过SqlCommand.ExecuteReader()从我的C#程序执行查询时,就是这种情况。调用(或不调用) DBCC FREEPROCCACHEDBCC dropcleanbuffers没有区别;使用OPTION (RECOMPILE)时,查询结果总是即时返回,如果不调用,则返回时间长于5分钟。出于此测试的目的,总是使用相同的参数调用查询。

我使用的是SQL Server 2008。

我对编写SQL相当满意,但以前从未在查询中使用过OPTION命令,在浏览此论坛上的帖子之前,我对计划缓存的整个概念并不熟悉。我从这些帖子中理解到,OPTION (RECOMPILE)是一个昂贵的操作。显然,它为查询创建了一个新的查找策略。那么,为什么省略OPTION (RECOMPILE)的后续查询会如此缓慢呢?后续查询不应该使用在包含重新编译提示的前一次调用中计算的查找策略吗?

在每次调用时都需要重新编译提示的查询是不是很不寻常?

对于这个入门级的问题,我很抱歉,但我真的搞不懂。

更新:我被要求发布查询...

代码语言:javascript
复制
select acctNo,min(date) earliestDate 
from( 
    select acctNo,tradeDate as date 
    from datafeed_trans 
    where feedid=@feedID and feedDate=@feedDate 

    union 

    select acctNo,feedDate as date 
    from datafeed_money 
    where feedid=@feedID and feedDate=@feedDate 

    union 

    select acctNo,feedDate as date 
    from datafeed_jnl 
    where feedid=@feedID and feedDate=@feedDate 
)t1 
group by t1.acctNo
OPTION(RECOMPILE)

当从Query Analyzer运行测试时,我预先考虑了以下几行:

代码语言:javascript
复制
declare @feedID int
select @feedID=20

declare @feedDate datetime
select @feedDate='1/2/2009'

当从我的C#程序调用它时,参数是通过SqlCommand.Parameters属性传入的。

出于本文讨论的目的,您可以假设参数永远不会改变,因此我们可以排除次优的参数嗅觉作为原因。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2014-01-01 11:41:03

有些时候,使用OPTION(RECOMPILE)是有意义的。根据我的经验,只有在使用动态SQL时,这才是可行的选择。在您探索这在您的情况下是否有意义之前,我建议重新构建您的统计数据。这可以通过运行以下命令来完成:

代码语言:javascript
复制
EXEC sp_updatestats

然后重新创建你的执行计划。这将确保在创建执行计划时,它将使用最新信息。

每次执行查询时,添加OPTION(RECOMPILE)都会重新构建执行计划。我从来没有听说过它被描述为creates a new lookup strategy,但也许我们只是对同一件事使用了不同的术语。

在创建存储过程时(我怀疑您是从.NET调用即席sql,而不是从if you are using a parameterized query then this ends up being a stored proc call调用),SQL Server会尝试根据数据库中的数据和传入的参数(parameter sniffing)来确定此查询的最有效执行计划,然后缓存此计划。这意味着,如果您在数据库中有10条记录的情况下创建查询,然后在有100,000,000条记录时执行该查询,则缓存的执行计划可能不再是最有效的。

总而言之,我看不出OPTION(RECOMPILE)在这里有什么好处。我怀疑你只需要更新你的统计数据和你的执行计划。根据您的情况,重新构建统计信息可能是DBA工作的重要部分。如果你在更新你的统计数据后仍然有问题,我建议你发布两个执行计划。

回答你的问题-是的,我想说的是,你的最佳选择是在每次执行查询时重新编译执行计划,这是非常不寻常的。

票数 185
EN

Stack Overflow用户

发布于 2014-05-30 04:34:08

通常,当查询的运行与运行之间存在巨大差异时,我发现这通常是5个问题之一。

  1. STATISTICS -统计数据已过期。数据库在表和索引的不同列中存储有关值类型的范围和分布的统计信息。这有助于查询引擎为它将如何进行查询制定一个“攻击计划”,例如,它将使用散列或查找整个集合来匹配表之间的键的方法类型。可以对整个数据库调用Update Statistics,也可以只对某些表或索引调用Update Statistics。这会使查询从一次运行减慢到另一次运行,因为当统计数据过期时,对于同一查询的新插入或更改的数据,查询计划可能不是最佳的(下面将详细解释)。在生产数据库上立即更新统计数据可能并不合适,因为根据要采样的数据量,可能会有一些开销、速度减慢和滞后。您还可以选择使用完全扫描或采样来更新统计信息。如果查看查询计划,则还可以使用命令DBCC SHOW_STATISTICS (tablename,indexname)查看正在使用的索引的统计信息。这将向您显示查询计划用于建立其方法on.
  2. PARAMETER SNIFFING的键的分布和范围-缓存的查询计划对于您传递的特定参数并不是最优的,即使查询本身没有更改。例如,如果传递的参数仅检索1,000,000行中的10行,则创建的查询计划可能使用散列联接,但是如果传递的参数将使用1,000,000行中的750,000行,则创建的计划可能是索引扫描或表扫描。在这种情况下,您可以告诉SQL语句使用选项RECOMPILE选项(RECOMPILE)或用于RECOMPILE的SP。告诉引擎这是一个“单次使用计划”,不使用缓存的计划,这可能不适用。没有关于如何做出这个决定的规则,它取决于知道users.
  3. INDEXES使用查询的方式-查询可能没有改变,但是其他地方的改变,比如删除了一个非常有用的索引,已经减慢了query.
  4. ROWS改变的-你要查询的行在调用之间发生了巨大的变化。在这些情况下,通常会自动更新统计信息。但是,如果您正在构建动态SQL或在紧密循环中调用SQL,则有可能基于错误的大量行数或统计数据使用过时的查询计划。同样在这种情况下,选项(重新编译)逻辑是useful.
  5. THE it the Logic,您的查询不再有效,它对于少量的行很好,但不再具有伸缩性。这通常涉及对查询计划的更深入的分析。例如,您不能再批量地做事情,而必须分块并进行较小的提交,或者您的Cross Product对于较小的集合很好,但现在随着它的规模变大,它会占用CPU和内存,这也可能适用于使用DISTINCT,您正在为每一行调用一个函数,您的键匹配由于强制类型转换或NULLS或函数而不使用索引……这里有太多的可能性。

通常,在编写查询时,您应该对某些数据在表中的大致分布情况有一定的了解。例如,一列可以具有均匀分布的不同值的数量,也可以是倾斜的,80%的时间具有一组特定的值,无论分布是随时间频繁变化还是相当静态。这将使您更好地了解如何构建高效的查询。而且在调试查询性能时具有建立关于其为什么缓慢或低效的假设的基础。

票数 166
EN

Stack Overflow用户

发布于 2015-10-04 09:52:53

为了添加到选项(重新编译)可能非常有用的情况的优秀列表(由@CodeCowboyOrg给出),

  1. Table变量。在使用表变量时,表变量不会有任何预先构建的统计信息,这通常会导致查询计划中的估计行与实际行之间存在较大差异。在带有表变量的查询上使用选项(RECOMPILE)可以生成一个查询计划,该计划可以更好地估计所涉及的行数。我特别关键地使用了一个无法使用的表变量,并且我打算放弃它,直到我添加了选项(重新编译)。运行时间从几个小时到几分钟。这可能是不寻常的,但无论如何,如果您正在使用表变量并致力于优化,那么很有必要看看选项(重新编译)是否会有所不同。
票数 35
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20864934

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档