我们知道SqlServer的查询优化器会将所执行的Sql语句的执行计划作缓存,如果后续查询可以复用缓存中的执行计划,那么SqlServer就会为后续查询复用执行计划而不是重新生成一个新的执行计划,因为复用执行计划的性能比生成执行计划的性能要高很多,所以SqlServer的这一特性可以大大提高Sql语句的执行效率。特别是对于存储过程,因为存储过程的执行计划是在存储过程第一次执行的时候生成的,存储过程的执行计划生成后就会被缓存到SqlServer的执行计划列表中,如果以后存储过程再被执行,那么存储过程的执行计划就可以被复用(除非查询优化器认为该存储过程的执行计划已经过时,否则一般都会被复用),性能大大提升。
那么现在我们怎么才能知道执行的Sql语句是复用的SqlServer缓存的执行计划,还是重新生成的执行计划呢?
我们可以通过Sql Server Profiler这个工具来看到执行计划是否被查询优化器复用。
首先打开Sql Profiler,新建一个跟踪
然后在 事件选择 面板上选中 显示所有事件
然后在事件列表里面,选中 Stored Procedures 类别下的 SP:CacheHit 和 SP:CacheMiss 事件,如果Sql Profiler中出现了SP:CacheHit事件表示SqlServer为查询语句复用了缓存中的执行计划,如果出现了SP:CacheMiss 事件表示SqlServer为查询语句重新生成了执行计划
接着我们随便执行一个Sql语句如下
select * from [dbo].[T_People]
从下图中我们发现在Sql Profiler出现了SP:CacheMiss 事件,因为我们是在SqlServer中第一次执行该查询,所以SqlServer的缓存列表中并没有该查询语句的执行计划,所以SqlServer为该查询语句重新生成了执行计划。
接着我们再次执行上面的查询语句,这一次Sql Profiler出现了SP:CacheHit 事件,说明SqlServer这次为查询语句复用了缓存中的执行计划,并没有重新生成执行计划。
使用如下语句可以清除SqlServer目前所有缓存的执行计划,为所有Sql语句重新生成执行计划,切记不要在客户生产环境上执行如下语句!
DBCC FREEPROCCACHE
所以通过Sql Profiler我们可以跟踪到执行的每条Sql语句是否重新生成了执行计划,从而知道对查询性能的影响是什么。对于SqlServer是否会为查询语句复用执行计划也是一个非常复杂的问题,诸如查询条件参数化这样的手段都可以增加执行计划的复用性,有兴趣的朋友可以参考下面三篇文章做详细了解,这三篇文章都详细地解释了SqlServer执行计划的复用机制,写的非常全面。
谈一谈SQL Server中的执行计划缓存(上)
谈一谈SQL Server中的执行计划缓存(下)
执行计划的重用