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

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

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


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

 DBCC FREEPROCCACHE

 SELECT * FROM Customers SELECT * FROM Orders
GO
SELECT * FROM Customers SELECT * FROM Orders SELECT cacheobjtype, objtype, usecounts, sql FROM sys.syscacheobjects
WHERE sql NOT LIKE '%cache%' AND sql NOT LIKE '%sys.%'

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

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


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

 CREATE PROC spCust1 @CustID NVARCHAR(5)
AS
SELECT * FROM dbo.Customers
WHERE CustomerID=@CustID
GO EXEC spCust1 'ALFKI'
EXEC spCust1 'BERGS' --DBCC FREEPROCCACHE
SELECT cacheobjtype, objtype, usecounts, sql FROM sys.syscacheobjects
WHERE sql NOT LIKE '%cache%' AND sql NOT LIKE '%sys.%'

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


图 3

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

还有其他进阶的选项应用,像是可以在创建存储过程时,使用 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 选项。现在回想起来,其实是不必加的,因为重复用旧的「执行计划」即可 (可节省许多数据库伺服器上的资源),丢入的参数也都差不多 (用户目前所在页数、每页要传回几条记录)。

 CREATE PROCEDURE [dbo].[GridView_pager]
@StartRowIndex int,
@PageSize int,
@tableName nvarchar(50),
@columnName nvarchar(100),
@sqlWhere nvarchar(1000),
@groupBy nvarchar(100),
@orderBy nvarchar(100),
@rowCount int output
WITH RECOMPILE
AS

相关文章 :

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


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

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

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 遇到的问题(Problems) 实现代码(SQL Codes) 方法一:拼接SQL: 方法二: ...

  2. Oracle Stored Procedure demo

    1.how to find invalid status stored procedure and recompile them? SELECT OBJECT_NAME , status FROM u ...

  3. SQL Server——存储过程(Stored Procedure)、事物、触发器

    存储过程(proc 或 procedure) 存储过程(Stored Procedure),计算机用语,是一组为了完成特定功能的SQL语句集,是利用SQL Server所提供的Transact-SQL ...

  4. 数据库之存储过程(Stored Procedure)【未完待续】

    存储过程(Stored Procedure,以下简称SP)是啥?有什么用?优缺点? 一个SP是一段存储在数据库系统中的一条或多条sql语句的集合,类似一条批处理,它能被触发器,或者其他的SP以及APP ...

  5. stored procedure --存储过程

    存储过程(Stored Procedure),计算机用语,是一组为了完成特定功能的SQL语句集,是利用SQL Server所提供的Transact-SQL语言所编写的程序.经编译后存储在数据库中.存储 ...

  6. [C++中级进阶]001_C++0x里的完美转发到底是神马?

    [C++中级进阶]001_C++0x里的完美转发到底是神马? 转载至:http://www.cnblogs.com/alephsoul-alephsoul/archive/2013/01/10/285 ...

  7. [转]Dynamic SQL & Stored Procedure Usage in T-SQL

    转自:http://www.sqlusa.com/bestpractices/training/scripts/dynamicsql/ Dynamic SQL & Stored Procedu ...

  8. [原] XAF How to bind a stored procedure to a ListView in XAF

    First, I suggest that you review the following topic to learn how to show a custom set of objects in ...

  9. Retrieving Out Params From a Stored Procedure With Python

    http://www.rodneyoliver.com/blog/2013/08/08/retrieving-out-params-from-a-stored-procedure-with-pytho ...

随机推荐

  1. gcc编译器用法(自学总结)

    GCC仅仅意味着GNU C Compiler. gcc工作四个步骤:预处理,编译,汇编,连接. 1.预处理: 编译器将C源代码中的包含的头文件如stdio.h编译进来,用户可以使用gcc的选项&quo ...

  2. linux python更新

    linux的yum依赖自带的Python,为了防止错误,此处更新其实是再安装一个Python 1.查看默认python版本 python -v 2.安装gcc,用于编辑Python源码 yum ins ...

  3. 【iOS atomic、nonatomic、assign、copy、retain、weak、strong】的定义和区别详解

    一.atomic与nonatomic 1.相同点 都是为对象添加get和set方法 2.不同点 atomic为get方法加了一把安全锁(及原子锁),使得方法get线程安全,执行效率慢 nonatomi ...

  4. Oracle的tnsnames.ora配置(PLSQL Developer)

    首先打开tnsnames.ora的存放目录,一般为D:\app\Administrator\product\11.2.0\client_1\network\admin,就看安装具体位置了. 步骤阅读 ...

  5. [spring源码学习]二、IOC源码——配置文件读取

    一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public cl ...

  6. Redis——学习之路四(初识主从配置)

    首先我们配置一台master服务器,两台slave服务器.master服务器配置就是默认配置 端口为6379,添加就一个密码CeshiPassword,然后启动master服务器. 两台slave服务 ...

  7. BZOJ1129 : [POI2008]Per

    枚举LCP,假设前$i-1$个都相同.那么后面$n-i$个数可以随意排列,第$i$个位置可以填的方案数为后面小于$a_i$的数字个数,树状数组维护. 同时为了保证本质不同,方案数需要除以每个数字的个数 ...

  8. bzoj3673可持久化线段树实现可持久化数组实现可持久化并查集(好长)

    线段树只用叶子节点感觉莫名浪费,,, 感觉真好写(刚从未来程序逃回来的人) #include <cstdio> #define mid ((l+r)>>1) ,ca,x,y; ...

  9. 【BZOJ】4144: [AMPPZ2014]Petrol

    题意 给定一个\(n\)个点.\(m\)条边的带权无向图,其中有\(s\)个点是加油站.每辆车都有一个油量上限\(b\),即每次行走距离不能超过\(b\),但在加油站可以补满.\(q\)次询问,每次给 ...

  10. C#输出文字对齐,空格位数对齐

    Align String with Space This example shows how to align strings with spaces. The example formats tex ...