缓存壳查询的目的在于当执行与壳查询完全相同的sql时,查询语句可以快速地找到其对应的真正的执行计划”,
?
此时虽然真正使用的是参数化执行计划,但是DMV中只是将壳查询的usecounts计数器加1
?
那么回头再想一个问题,对于简单参数模式下,SqlServer什么情况下回对sql语句自动参数化?
?
简单模式下,SqlServer并不是所有的sql都进行参数化处理,只有对那些有且只有一种执行计划的sql语句,才自动参数化处理,
?
比如上面的查询,因为t_1表上的id列上没有任何索引,不管对于任何一个值,都只能是全表扫描的方式去执行这个查询,此时SqlServer会做到自动参数化,生成一个可重用的执行计划。
?
如果id列上有一个非唯一的索引,那么select * from t_1 where id=***这个查询就有可能存在不同的执行计划,
?
比如是索引查询或者是全表扫描,这个要依据列上的统计信息了(这个话题也比较大,就不展开说了),
?
也就是说,在不同的查询条件下,有可能生成不同的执行计划,那么SqlServer就不会为其生成参数化的sql。
?
比如在id列上见一个非唯一的索引,那么再次观察执行计划缓存,就发现SqlServer并没有生成一个自动参数化的执行计划。
--测试之前注意清空一下执行计划缓存
dbcc freeproccache
--在id列上创建一个非唯一的索引
create index idx_id on t_1(id)
--此时执行这个查询
select * from t_1 where id=1
--查看执行计划的缓存
select usecounts,size_in_bytes,objtype,t.text
from sys.dm_exec_cached_plans p cross apply sys.dm_exec_sql_text(p.plan_handle) t
where p.cacheobjtype='Compiled Plan'
and t.text like '%t_1%'
and t.text not like '%dm_exec_cached_plans%'
?
?
此时会发现,SqlServer并没有自动地生成一个参数化的sql,就是因为对于select * from t_1 where id=1这个查询
?
可能索引查找是最优化的,但是如果把id的值换做另外其他的未知的值,可能表扫描是最后化的,也就是说,在这种情况下,当前查询的执行计划不具备通用性
?
所以此时SqlServer并不会生成自动参数化的sql执行计划。
?
总结:SqlServer在执行sql的的生成执行计划的时候,除了人为因素(比如参数化的sql)的影响,SqlServer本身也会对一些没有参数化的sql做自动参数化,以最优化的方式去运行sql指令,提高执行效率的目的。