Stored Procedure 里的 WITH RECOMPILE 到底是干麻的?

原文:Stored Procedure 里的 WITH RECOMPILE 到底是干麻的?

在 SQL Server 创建或修改「存储过程(stored procedure)」时,可加上 WITH RECOMPILE 选项,但多数文档或书籍都写得语焉不详,或只解释为「每次执行此存储过程时,都要重新编译」。事实上,是指执行此一存储过程时,要强制重新产生「执行计划(execution plan)」,而不要从「缓存(cache)」去取得旧的「执行计划」。

SQL Server 在评估与产生「执行计划」时,非常耗 CPU 资源,因此,如何让其正确地从 cache 中,重复使用旧的「执行计划」就很重要;但是,若误用旧的「执行计划」,导致 SELECT 查询的性能大幅下降,则更得不偿失。

一般的 SQL 查询,两次或多次执行的 SQL 语句中,内容必须完全符合,才能延用旧的「执行计划」,包含: 大小写、换行、空白。如下图 1,因为两次执行的 SQL 语句,差了一个「半形空格」,导致产生了两次「执行计划」,而无法重复使用旧的「执行计划」。


图 1 浪费资源产生了两次「执行计划」

1 DBCC FREEPROCCACHE
2
3 SELECT * FROM Customers SELECT * FROM Orders
4 GO
5 SELECT * FROM Customers  SELECT * FROM Orders
6
7 SELECT cacheobjtype, objtype, usecounts, sql FROM sys.syscacheobjects
8 WHERE sql NOT LIKE '%cache%' AND sql NOT LIKE '%sys.%'

View Code

若是改用「参数化查询」,如下 :
SELECT * FROM Customers WHERE CustomerID=@CustomerID
即可避免因参数值不同,一直产生新的「执行计划」,亦可避免 SQL Injection 攻击。

而存储过程,相对于一般 SQL 语句,其在性能上的优势,除了已事先编译外,存储过程也可提升「执行计划」的重用性(复用性),避免产生新的「执行计划」、消耗 CPU 资源。如下图 2,两次调用同一个存储过程时,但传入不同的参数,SQL Server 会重复使用同一个「执行计划」,如同上述的「参数化查询」一样,不会浪费资源产生新的「执行计划」。


图 2 「执行计划」被重复使用,避免浪费资源

 1 CREATE PROC spCust1 @CustID NVARCHAR(5)
 2 AS
 3 SELECT * FROM dbo.Customers
 4 WHERE CustomerID=@CustID
 5 GO
 6
 7 EXEC spCust1 'ALFKI'
 8 EXEC spCust1 'BERGS'
 9
10 --DBCC FREEPROCCACHE
11 SELECT cacheobjtype, objtype, usecounts, sql FROM sys.syscacheobjects
12 WHERE sql NOT LIKE '%cache%' AND sql NOT LIKE '%sys.%'

View Code

但若存储过程「数据内容分布不平均」,例如某个 Table,里面有个 Int 类型的字段,大量记录里所存储的值依序为 1~100,但只有某一条记录存的是 10000。亦即符合过滤条件的记录有时极多 (「执行计划」适合用「索引扫描」),但有时符合的只有一两条 (「执行计划」适合用「索引查找」)。而未来在调用此存储过程时,两种情境都有可能出现,因此我们希望此一存储过程,在执行时「不要 cache 执行计划」,亦即让此存储过程在每次执行时,都重新评估、产生最适当的「执行计划」,此时就可加上 WITH RECOMPILE 选项。或者如下图 3,丢给前端应用程序去决定,亦即 AP 在调用此存储过程时,再决定是否加上 WITH RECOMPILE 参数。


图 3

1 Exec select_Proc1 @Key1=5       --自動選用高效能的「執行計畫」
2 Exec select_Proc1 @Key1=10000   --從 cache 延用舊的「執行計畫」,因不適用,反而導致效能不佳
3 Exec select_Proc1 @Key1=10000 WITH RECOMPILE --強制重新產生新的、高效能「執行計畫」

View Code

还有其他进阶的选项应用,像是可以在创建存储过程时,使用 OPTIMIZE FOR 选项,只针对特定某一个参数值来做 cache,来产生固定一种、平均对性能影响最小的「执行计划」,又能避免一直重复产生新的「执行计划」而浪费 CPU 资源。



案例分析 - 同样的语法在存储过程内跑很慢,单独跑很快 (胡百敬, 繁体中文) :
http://byronhu.wordpress.com/2010/07/15/with-recompile/

引用该文部分内容 :

朋友问了一个有趣的问题:同样的语句,在存储过程内跑很慢,单独跑很快。

存储过程会缓存执行计划 (若未加上 WITH RECOMPILE),一般来说可以省掉 CPU 耗费。但若两次执行此存储过程的期间,所引用的记录数量差异很大,则第二次执行时沿用旧的执行计划,性能会变得很差。可以观察以下现象:

  1. 观察执行后的执行计划,传回大量记录却是用「索引查找」。
  2. 透过 Profiler 观察存储过程内的语法,和单独执行的语法,所耗的 IO/CPU/Duration 的数值。若将某句的语法单独拿到 Management Studio 执行的性能,远好于该句语法在存储过程内执行,就有可能是上述原因。

简单的解法,是在执行或创建存储过程时,搭配 WITH RECOMPILE 选项。

...中间略...

存储过程的执行情境可以分 80-20 定律,若少数执行状况 AP 自己知道,则 AP 可以判读是否要下 with recompile 或是撰写存储过程直接搭配 Option(Optimize for (参数定义))

但在一些状况,例如使用者下 Range 查询,或是「财务滚算」数据,会大量删除、插入中继表内的数据,developer 无法预先评估可能的数据量大小,则在存储过程创建时,直接搭配 with recompile,可得到较稳定的执行性能。



结语: 我自己早年写 AP 时,一直查不到 WITH RECOMPILE 是干麻的,当时我写用来「分页(换页)」的存储过程时 (双 TOP 夹击、或 ROW_NUMBER 函数),就一律加上 WITH RECOMPILE 选项。现在回想起来,其实是不必加的,因为重复用旧的「执行计划」即可 (可节省许多数据库伺服器上的资源),丢入的参数也都差不多 (用户目前所在页数、每页要传回几条记录)。

 1 CREATE PROCEDURE [dbo].[GridView_pager]
 2 @StartRowIndex    int,
 3 @PageSize int,
 4 @tableName nvarchar(50),
 5 @columnName nvarchar(100),
 6 @sqlWhere nvarchar(1000),
 7 @groupBy nvarchar(100),
 8 @orderBy nvarchar(100),
 9 @rowCount int output
10 WITH RECOMPILE
11 AS

View Code



相关文章 :

谈一谈 SQL Server 中的执行计划缓存
http://www.cnblogs.com/CareySon/archive/2013/05/04/3058592.html
http://www.cnblogs.com/CareySon/archive/2013/05/04/PlanCacheInSQLServerPart2.html


时间: 2024-09-11 14:28:27

Stored Procedure 里的 WITH RECOMPILE 到底是干麻的?的相关文章

SQL Server 在多个数据库中创建同一个存储过程(Create Same Stored Procedure in All Databases)

原文:SQL Server 在多个数据库中创建同一个存储过程(Create Same Stored Procedure in All Databases) 一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 遇到的问题(Problems) 实现代码(SQL Codes) 方法一:拼接SQL: 方法二:调用模板存储过程创建存储过程: 总结 扩展阅读 参考文献(References) 二.背景(Contexts) 在我的数据库服务器上,同一个实例

运用Stored Procedure验证login的输入

本文提供一种运用Stored Procedure验证login输入的方法,这种方法与目前大多数ASP程序的验证方法相比,执行效率高,代码简捷.在这里我运用了一个sp_login的SP来获得customerID,然后把它作为Session全程使用.看了许多商城代码,大多数使用cookie来保存,我认为不是一种好的方法.另外,运用COMMAND对象连接ADO是执行效率最高的方法,可以参考MSDN的相关文章,这是MS推荐的连接方法.在以后的文章中,我将频繁使用COMMAND对象和Stored Proc

Stored Procedure(存储过程)编写经验和优化措施

存储过程|优化 Stored Procedure(存储过程)编写经验和优化措施 一.前言:在经过一段时间的存储过程开发之后,写下了一些开发时候的小结和经验与大家共享,希望对大家有益,主要是针对Sybase和SQL Server数据库,但其它数据库应该有一些共性. 二.适合读者对象:数据库开发程序员,数据库的数据量很多,涉及到对SP(存储过程)的优化的项目开发人员,对数据库有浓厚兴趣的人. 三.介绍:在数据库的开发过程中,经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作

User Tips: Using Return Values from a SQL Server Stored Procedure to Customize Error Messages

error|server When I started developing web pages that interact with a SQL Server database, I probably started like everbody else: with inline SQL statements. I then progressed to using the connection object to call stored procedures and eventually st

jsp-我不懂这个js里的eval函数到底在哪里用到了

问题描述 我不懂这个js里的eval函数到底在哪里用到了 详细的代码如下var navigator_appName = ""chrome"";var window;var dbits;var canary=0xdeadbeefcafe;var j_lm=((canary&0xffffff)==0xefcafe);function BigInteger(abc){if(a!=null)if(""number""==typ

procedure db job-怎样在procedure里写log日志

问题描述 怎样在procedure里写log日志 最近要做一个DB job的feature做数据备份,但是其中一个需求是当程序出错时要用log记录出错的那一条数据,我在想我用的是:insert into (AB)TABLE1 select A B FROM TABLE1@DB_LINK 语句进行备份,这个如果失败的话不是整个都不成功吗?那如何才能记录出错的那条呢?这个可以实现吗?在proc里怎么写日志呢?求帮助啊 解决方案 用 try catch 还有个 @@error .

JDBC连接执行 MySQL 存储过程报权限错误:User does not have access to metadata required to determine stored procedure parameter types. If rights can not be granted,

国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送)国内私募机构九鼎控股打造,九鼎投资是在全国股份转让系统挂牌的公众公司,股票代码为430719,为"中国PE第一股",市值超1000亿元.  -----------------------------------------------------------------------------

码农们每天到底在干嘛?

摘要: 腾讯科技讯 (王冠)对于绝大多数网友来说,产品开发都是一件很神秘的事情.那些天书般的代码经过程序猿.工程狮们的双手敲击,就能产生各种奇妙的画面和有趣功能. 从用户的 腾讯科技讯(王冠)对于绝大多数网友来说,产品开发都是一件很神秘的事情.那些天书般的代码经过程序猿.工程狮们的双手敲击,就能产生各种奇妙的画面和有趣功能. 从用户的角度看,产品一直都是稳定而简洁的.那些码农们每天都在敲啊敲的,他们到底在干嘛?有人说,我知道,有个家伙用了一个星期写了个游戏,然后他让一亿人一起打飞机-- 多么壮观

双十二,淘宝到底想干啥?

与双十一所谓"网购 "所不同的是,双十二看似极其冷清.阿里到处在宣扬双十一创下的http://www.aliyun.com/zixun/aggregation/37072.html">191亿流水的傲人战绩,但对双十二跑了多少流水却讳莫如深.在策划双十二之初,网上就有言论对此表示很不看好,因为刚刚在双十一疯狂抢购了一把,消费者可能会囊中羞涩或钝感,不再进行网购.双十二被看衰到以至于网上出现了这样的流言:陆兆禧因双十二业绩未达标而被马云夺去淘宝CEO职衔--不过,事实上陆