执行计划--Adhoc和Prepare
在和SQLPass讨论adhoc和Prepare时,有各自不同的观点,我来发表下我的理解,不对之处,敬请指出!
Adhoc(即席查询):没有参数化的查询计划会被标记为adhoc,adhoc不能理解为该执行计划不会被重用。
Prepared(预定义):查询中使用到参数的执行计划会被标记为Prepared.
在后续测试中,每次测试之前需要清除执行计划:
--清理执行计划
DBCC FREEPROCCACHE
测试语句执行结束后需要使用以下语句来查看执行计划:
--查看执行计划
select cp.usecounts as '使用次数',cp.cacheobjtype as '缓存类型',
cp.objtype as [对象类型],
st.text as 'TSQL',
--cp.plan_handle AS '执行计划',
qp.query_plan as '执行计划',
cp.size_in_bytes as '执行计划占用空间(Byte)'
from sys.dm_exec_cached_plans cp
cross apply sys.dm_exec_sql_text(plan_handle) st
cross apply sys.dm_exec_query_plan(plan_handle) qp
ORDER BY[对象类型]
测试1:简单查询
--执行两遍
SELECT *FROM [TestDB].[dbo].[TB1] WHERE ID=3
执行结果:
可以看到,生成了一个Adhoc执行计划和一个Prepared执行计划,其中Adhoc执行计划被执行两次,证明Adhoc执行计划也是可以被重用的,而Prepared执行计划是由于“简单参数化”的原因生成的。
(PS:在该场景中,Adhoc执行计划最终使用的是Prepared执行计划来执行的,因此可以发现Prepared的执行计划占用的空间更多一些)
测试2:使用sp_executesql来实现参数化查询
--执行两遍
EXEC sp_executesql N'SELECT *FROM [TestDB].[dbo].[TB1] WHERE ID=@ID',N'@ID INT',@ID=2
执行结果:
可以看到在TSQL列里有明显的参数,因此该执行计划被标记为Prepared,同时该计划被执行两遍
测试3:使用sp_executesql来实现非参数化查询
--执行两遍
EXEC sp_executesql N'SELECT *FROM [TestDB].[dbo].[TB1] WHERE ID=3'
执行结果:
可以看到,即使使用sp_executesql,但由于TSQL里没有使用参数,因此执行计划仍然被标记为Adhoc。
测试4:使用sp_executesql来实现混合查询
--执行两遍
EXEC sp_executesql N'SELECT *FROM [TestDB].[dbo].[TB1] WHERE ID=3 AND C1=@C1',N'@C1 INT',@C1=3
执行结果:
可以发现,只有含有一部分的参数,执行计划就会被标记为Prepared
测试5:使用sp_executesql来实现混合查询2
--执行两遍
EXEC sp_executesql N'SELECT *FROM [TestDB].[dbo].[TB1] WHERE ID=3',N'@C1 INT',@C1=3
执行结果
在上面的测试中,查询根本没有使用到参数C1,但是由于整个查询里有参数,所以仍被标记为Prepared。
综上所述,只有查询计划里有参数,执行计划就标记为Prepared,如果没有参数,就会标记为Adhoc.
SQL SERVER 会在两个环节考虑是否有可重用执行计划
1>在解析SQL语句之前,对SQL语句进行hash的到一个key,使用这个key去查找是否存在现成的执行计划;
2>将SQL解析成语法树后,再使用语法树的hash key去寻找是否存在现成的执行计划。
为证明上述观点,我们做以下测试:
SELECT *FROM [TestDB].[dbo].[TB1] WHERE ID=3
SELECT * FROM [TestDB].[dbo].[TB1] WHERE ID=3
测试结果:
两条语句中有一个空格的差别,因此会生成两个adhoc执行计划,但是只会生成一个Prepared执行计划,表明这两个Adhoc执行计划最终都使用该Prepeared的执行计划。
Adhoc执行计划会调用Prepared执行计划,但Prepared执行计划不会调用Adhoc执行计划,这是两者的另一区别。
误区:Adhoc会导致重编译,Adhoc就是影响性能,就是需要把Adhoc查询改成Prepared查询
这个是初学者很容易犯的误区,容易把问题一刀切,由于我们需要在查询里使用到不同的变量,如"WHERE ID=1"和"WHERE ID=2"这样的语句,会生成不同的adhoc的执行计划,每个执行计划生成会消耗CPU资源,并需要占用buffer pool里的内存,当频繁执行这些类似但又不相同的SQL语句时,就会浪费大量的资源,因此需要将之参数化,共用一个执行计划,尤其在执行复杂SQL(如四五个表做连接查询)时,查询优化器需要分析生成很多执行计划并选择一种比较合理的执行计划来执行,消耗很多CPU资源并延长总的SQL执行时间,共用一个执行计划会大大提升系统性能。
当然,参数化也有其切点,在数据分布不均或参数变动对查询影响巨大的情况下,参数化反而会导致系统异常,如果“WHERE ID>@ID”语句,当ID=10000000时返回一条数据,而当ID=1是返回10000000条数据,前者适合索引查找,后者适合全表扫描,如果两者使用同一个执行计划,并会导致系统性能严重下降,此时Adhoc反而更适合。
此外,还有一种情况,当查询语句特别简单,简单到编译几乎不消耗资源时,SQL SERVER会选择不保存这些语句的执行计划。
在分析执行计划问题时,需要考虑以下问题:
1>系统是否有过多的adhoc执行计划占用大量内存
2>这些adhoc的执行频率和相似度
3>是否可以改写这些adhoc执行计划的SQL
4>是否可以使用'optimize for ad hoc workloads'来优化
5>是否可以使用'强制参数化'
推荐阅读:http://www.cnblogs.com/TeyGao/p/3526804.html
照例要上妹子一张,养眼和招狼:
执行计划--Adhoc和Prepare的更多相关文章
- SQL Server中参数化SQL写法遇到parameter sniff ,导致不合理执行计划重用的一种解决方案
parameter sniff问题是重用其他参数生成的执行计划,导致当前参数采用该执行计划非最优化的现象.想必熟悉数据的同学都应该知道,产生parameter sniff最典型的问题就是使用了参数化的 ...
- 浅析SqlServer简单参数化模式下对sql语句自动参数化处理以及执行计划重用
我们知道,SqlServer执行sql语句的时候,有一步是对sql进行编译以生成执行计划, 在生成执行计划之前会去缓存中查找执行计划 如果执行计划缓存中有对应的执行计划缓存,那么SqlServer就会 ...
- Sql Server之旅——第十一站 简单说说sqlserver的执行计划
我们知道sql在底层的执行给我们上层人员开了一个窗口,那就是执行计划,有了执行计划之后,我们就清楚了那些烂sql是怎么执行的,这样 就可以方便的找到sql的缺陷和优化点. 一:执行计划生成过程 说到执 ...
- sqlserver的执行计划
一:执行计划生成过程 说到执行计划,首先要知道的是执行计划大概生成的过程,这样就可以做到就心中有数了,下面我画下简图: 1. 分析过程 这三个比较容易理解,首先我们要保证sql的语法不能错误,sele ...
- SQLServer中的执行计划缓存由于长时间缓存对性能造成的干扰
本文出处:http://www.cnblogs.com/wy123/p/7190785.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...
- MySQL— 索引,视图,触发器,函数,存储过程,执行计划,慢日志,分页性能
一.索引,分页性能,执行计划,慢日志 (1)索引的种类,创建语句,名词补充(最左前缀匹配,覆盖索引,索引合并,局部索引等): import sys # http://www.cnblogs.com/w ...
- (转)explain、db2exfmt 命令的使用:文本输出执行计划
原文:http://blog.51cto.com/freebile/1068610 db2有图形执行计划显示工具,如果没有图形环境,如unix主机,可以生成文本的文件来显示执行计划1.如果第一次执行, ...
- Sql Server中执行计划的缓存机制
Sql查询过程 当执行一个Sql语句或者存储过程时, Sql Server的大致过程是 1. 对查询语句进行分析,将其生成逻辑单元,并进行基本的语法检查 2. 生成查询树(会将查询语句中所有操作转换为 ...
- ORACLE从共享池删除指定SQL的执行计划
Oracle 11g在DBMS_SHARED_POOL包中引入了一个名为PURGE的新存储过程,用于从对象库缓存中刷新特定对象,例如游标,包,序列,触发器等.也就是说可以删除.清理特定SQL的执行计划 ...
随机推荐
- 20181205_C#窗体监听键盘事件
1. 需要设置窗体的 KeyPreview = true; 2. 如果窗体上有获取的了焦点的button按钮, 则监听不到 Enter事件, 需要取消按钮的焦点
- PHP中的=>,->,@,&,::,%
在php中数组默认键名是整数,也可以自己定义任意字符键名(最好是有实际意义).如: $css=array('style'=>'0',‘color’=>‘green‘), 则$css['st ...
- Python实现进度条总结
先说一下文本系统的控制符:\r: 将光标移动到当前行的首位而不换行:\n: 将光标移动到下一行,并不移动到首位:\r\n: 将光标移动到下一行首位. 环境:root@ubuntu16: ...
- rm 递归删除目录下某一类型文件
命令:find -name "*.js.map" | xargs rm -f 解释:find -name "*.js.map" 可以查到当前目录下(包括子目录, ...
- 不用写代码就能实现深度学习?手把手教你用英伟达 DIGITS 解决图像分类问题
2006年,机器学习界泰斗Hinton,在Science上发表了一篇使用深度神经网络进行维数约简的论文 ,自此,神经网络再次走进人们的视野,进而引发了一场深度学习革命.深度学习之所以如此受关注,是因为 ...
- 串口通信,帧与帧之间的时间间隔问题?9600波特率,帧将各在20ms以上
- Spring Boot实践——Spring AOP实现之动态代理
Spring AOP 介绍 AOP的介绍可以查看 Spring Boot实践——AOP实现 与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改 ...
- readlink 获取当前进程对应proc/self/exe
[readlink 获取当前进程对应proc/self/exe] shell中 readlink /proc/self/exe READLINK(2)NAME readlink - re ...
- Five reasons phosphorene may be a new wonder material
A material that you may never have heard of could be paving the way for a new electronic revolution. ...
- acoj-1735 输油管道 【中位数】
题目链接:http://acdream.info/problem?pid=1735 输油管道 Time Limit: 2000/1000MS (Java/Others) Memory Limit: 2 ...