本文出处:http://www.cnblogs.com/wy123/p/6913055.html

执行计划的缓存与重用

在通过SQL Profile观察一个SQL语句或者存储过程是否有可用的缓存执行计划的时候,
通过SP:CacheMiss和SP:CacheHit事件可以说明是否发生了编译/重编译和是否重用了缓存的执行计划,
但是对于SP:CacheMiss这一细节,还是存在不少理解错误的情况的,本文通过一个简单的例子来解释说明SP:CacheMiss所表达的真实含义。

简单建个测试表,来测试使用

CREATE TABLE Test
(
Id INT,
NAME VARCHAR(100)
)
GO DECLARE @i INT = 0
WHILE @i<100000
BEGIN
INSERT INTO Test VALUES(@i,NEWID())
SET @i = @i+1
END
GO CREATE INDEX IX_Id ON Test(Id)
GO

如何利用Profile观察SQL语句的执行计划的编译/重编译和重用?

  众所周知的,参数化SQL的执行计划可以缓存并重用,那么就以如下一个简单的参数化SQL为例,观察在传入不同参数时的执行计划重用现象
  下面是两个参数化的SQL语句,语句的主体都是一样的,只是带入的参数不同,正常情况下,第二句代码是可以重用第一句代码执行之后缓存的执行计划的。

  至于怎么开Profile就不说了,基础问题。

SP:CacheInsert和SP:CacheHit

  执行上述代码,如下

DBCC FREEPROCCACHE
GO EXEC SP_EXECUTESQL N'SELECT * FROM [dbo].[Test] WHERE Id = @id', N'@id INT',@id =9999
GO EXEC SP_EXECUTESQL N'SELECT * FROM [dbo].[Test] WHERE Id = @id', N'@id BIGINT',@id =201
GO

  得到的Profile中跟踪的信息如下

  简单说明一下,执行第一句代码之前,是清空了执行计划缓存的,所以第一次执行的sql语句是没有执行计划缓存可用的。

  参考截图。

  首先看第一次执行的情况:
    上面说了,执行第一句代码之前,是清空了执行计划缓存的,所以第一次执行的sql语句是没有执行计划缓存可用的。
    因此第一句SQL代码是需要编译的(不是重编译),
    参数化SQL编译之后要缓存起来(不同参数可以重用执行计划),表现就是有一个SP:CacheInsert。
    SP:CacheInsert的意思是当前SQL编译,生成了一个执行计划,并且向缓存中插入一个执行计划缓存。
  然后看第二次执行的情况:
    在第二句SQL执行的时候,因为第一句SQL已经编译并且缓存了一个执行计划,
    因此当前SQL是不需要编译,并且可以重用已有的执行计划的。
    这个就表现在有一个SP:CacheHit,
    SP:CacheHit的意思就是,当前SQL的执行计划在缓存的执行计划中命中。

为什么第一次和第二次都会出现一个“SP:CacheMiss”事件

  为什么第一次和第二次都会出现一个“SP:CacheMiss”事件?
  上面不是说第二个SQL的执行已经重用了第一次的执行计划了吗,为什么还会出现“SP:CacheMiss”事件?
  “SP:CacheMiss”事件到底代表什么含义?
  原因就是:
  SQL Server在缓存执行计划的时候,只缓存SQL语句本身,而不缓存执行的语句。
  听起来这么别扭,还是以实例来说明吧,参考下图,缓存就是换成的语句本身,而不是整个执行的字符串信息
  因此“SP:CacheMiss”代表的是:“EXEC SP_EXECUTESQL N'SELECT * FROM [dbo].[Test] WHERE Id = @id', N'@id INT',@id =8888”这个字符串。

  

  关于上述结论再举一例:

   如果上述实例不足以说明问题的话,再举一个例子,这里创建一个没有任何参数和动态SQL的存储过程(不会导致每次执行都重新编译,执行计划会重用),
   正常情况下,该存储过程第一次执行之后,执行计划会被缓存起来,第二次执行的时候就可以重用第一次的执行计划。

  

   这里情况缓存的执行计划,连续执行两次EXEC TestPlanCache,观察Profile中的现象,是不是还是每次执行仍有有一个SP:CacheMiss事件?
   为什么,难道说还是因为没有缓存可用吗?
   肯定不是,第一次执行仍旧是有一个SP:CacheInsert,第二次仍旧是SP:CacheHit,跟上述发生执行计划重用的现象一致。
   结论仍旧一样,与上面所述类似,SQL Server不会缓存EXEC TestPlanCache这个文本本身,缓存的执行计划是内部的SQL语句的执行计划,
   SP:CacheMiss是针对EXEC TestPlanCache这个命令来说的,SQL Server是不缓存调用存储过程或者参数化SQL的命令本身的。

  

总结:

有人在观察执行计划缓存与重用的时候,尤其是存储过程或者sp_executesql执行的参数化SQL语句,
会发现不停地出现SP:CacheMiss事件,就武断地断定为发生了编译/重编译,
编译与重编译是针对SQL语句或者存储过程中的SQL来说的,而不是针对调用存储过程或者参数化SQL的命令本身来说的。
SQL Server自身不会缓存调用存储过程或者参数化SQL的命令本身,因此会经常发现SP:CacheMiss事件。
对于SQL语句的计划缓存,如果是第一次编译,会缓存起来,缓存的时候就会出现SP:CacheInsert,第二次或者以后重用这个计划,就是出现SP:CacheHit事件。

SQL Server 利用Profiler观察执行计划是否重用时SP:Cachemiss,SP:CacheInsert以及SP:CacheHit的含义的更多相关文章

  1. sql server 数据库优化--显示执行计划

      刚开始用SQL Server的时候,我没有用显示执行计划来对查询进行分析.我曾经一直认为我递交的SQL查询都是最优的,而忽略了查询性能究竟如何,从而对“执行计划”重视不够.在我职业初期,我只要能获 ...

  2. SQL Server之看懂执行计划

    在SQL Server中,选中一段SQL按Ctrl+L,就可以查看它的执行计划. 上面是一个执行计划的实例,在SQL Server中,执行计划是从右往左看的. SQL Server中,查找数据的方式有 ...

  3. SQL SERVER 作业(或叫执行计划)

    如果在SQL Server 里需要定时或者每隔一段时间执行某个存储过程或3200字符以内的SQL语句时,可以用管理->SQL Server代理->作业来实现. 1.管理->SQL S ...

  4. SQL SERVER读书笔记:执行计划

    执行计划对性能影响甚大. 系统是怎么得出一个号的执行计划的?主要是依赖于准确的统计信息.统计信息准确的前提下,执行语句重用性高,可避免频繁编译,这也有助于提高性能. 但如果怀疑统计信息不够准确,可以强 ...

  5. SQL Server 查询分析器的执行计划中的扫描方式,举例理解

    student表,id,name,address id上建立聚集索引,Name建索引,address无索引.1. [Table Scan]:遍历整个表,查找所有匹配的记录行.这个操作将会一行一行的检查 ...

  6. [SQL Server]利用索引改善sql语句

    很多人不知道SQL语句在SQL SERVER中是如何执行的,他们担心自己所写的SQL语句会被SQL SERVER误解.比如: 1.select * from table1 where name=''z ...

  7. [sqlserver脚本]查看指定SQL语句生成了哪些执行计划

    参考SQL技术内幕写了一段脚本,可以通过这段脚本查看执行指定SQL语句后,系统生成了哪些执行计划.使用时注意以下几点: 修改use MyTest,换成自己的数据库名字. 将 exec sp_page_ ...

  8. SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程(支持单表或多表结查集分页)

    SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程,支持单表或多表结查集分页,存储过程如下: /******************/ --Author:梦在旅 ...

  9. sql server中如何查看执行效率不高的语句

    sql server中,如果想知道有哪些语句是执行效率不高的,应该如何查看呢?下面就将为您介绍sql server中如何查看执行效率不高的语句,供您参考.   在测量功能时,先以下命令清除sql se ...

随机推荐

  1. Linux查看DNS服务器及设置DNS服务器

    DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串. 一台主机的dn ...

  2. Java动手及实验整理

    1   枚举类型 在Java中,枚举类型本质上其实就是一个类,枚举中的常量都是该枚举类型的实例.枚举类型是引用类型!枚举不属于原始数据类型,它的每个具体值都引用一个特定的对象.相同的值则引用同一个对象 ...

  3. Java - 16 Java 方法

    在前面几个章节中我们经常使用到System.out.println(),那么它是什么呢? println()是一个方法(Method),而System是系统类(Class),out是标准输出对象(Ob ...

  4. 查看计算机CPU、内存使用情况

    Shift + Ctrl + Esc,打开Windows任务管理器,点击性能,如图: 可以清楚的看到整台机子的CPU.内存使用情况,其中CPU使用记录下有8个小窗口,因为博主的CPU是8核的,讲讲CP ...

  5. Linux服务器安装Nginx

    Nginx 安装 一.安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel 二.首先 ...

  6. 用Excel建模进行决策树分析

    决策树(Decision Tree)在机器学习中也是比较常见的一种算法,最早的决策树算法是ID3,改善后得到了C4.5算法,进一步改进后形成了我们现在使用的C5.0算法,综合性能大幅提高. 算法核心: ...

  7. day6--递归函数

    一递归函数 我们老师经常喜欢讲的一句话就是:人理解函数,神理解递归,那么什么是递归函数? 递归函数:在一个函数里面调用函数本身,也就是说这个函数里面出现了和函数一样的名字 例如: def func(n ...

  8. Vue.js路由

    有时候,我们在用vue的时候会有这样的需求,比如一个管理系统,点了左边的菜单栏,右边跳转到一个新的页面中,而且刷新的时候还会停留在原来打开的页面. 又或者,一个页面中几个不同的画面来回点击切换,这两种 ...

  9. 调试kettle插件

    http://wiki.pentaho.com/display/EAI/How+to+debug+a+Kettle+4+plugin

  10. JAVA操作字符串

    package com.test; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* ...