使用ssms和程序连接到实例,运行同一个proc的差异分析及解决
daniellin17(Q6):有个问题想请教大神石沫:有时候碰到 使用ssms和程序连接到实例,运行同一个proc,结果时间,io开销有明显的差距,执行计划也不一样。请帮忙分析一下原因,以及是否有什么解决办法。
石沫(A6):这个过程确实有遇到过,定位原因有多种可能。不过我们分析下面几个方向入手:
1. 执行计划缓冲分析
2. 统计信息分析
3. 存储过程重编译
4. 参数嗅探
执行计划缓冲,你可以观察到你的语句到底使用了那个查询计划:
SELECT
cp.usecounts
,objtype A
,st.[text]
,plan_handle
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(plan_handle)AS st
WHERE st.text LIKE ‘%********%’
对比你的两种查询计划,如果你确定哪种查询计划不是需要,但又被命中了,可以考虑将不需要的删除掉(但需要慎重),例如:
DBCC FREEPROCCACHE(0x060002007FEA040740C17E88000000003500000000000000)
查看你的统计信息情况,你可以。你可以看看你的统计信息是否失效,是否过时,同时更新统计信息使用FULLSAN扫描表或索引视图中的所有行来计算统计信息。同时查看一下相关执行计划变化对象的列的统计分布:
DBCC SHOW_STATITICS(***)
关于你的两种环境执行计划不一样,你提供的参数是否一致,有个参数嗅探的问题,不同的参数可能产生不一样的执行计划,有些执行计划是良好的,有些是给性能造成危害的。这个也需要关注一下,若确定是这个问题,解决这个的办法也很多,比如执行时加WITH RECOMMPILE。,还比如指定查询提示OPTIMIZE FOR等等。另外,你可以将输入参数赋予本地参数,强制优化器查看所引用的数据的统计来对可能使用的值做出好的评估。
存储过程重编译也是一种可能,大致原因有如下,可排查一下,不过根据你的描述应该不是这些原因,只是一个方向:
1. 常规表,临时表或者视图架构变化
2. 表列或者INDEX上的统计信息发生变化超过一定阈值
3. 执行计划老化并被释放
4. 显示调用sp_recompile
5. SET 选项变化
另外,你可以分析你的语句和变化的执行计划,创建一个更合理的INDEX可能会解决你的问题。同时,你也可以强制指定INDEX,使用WITH (FORCESEEK),不要使用WITH(INDEX=***)