在和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的更多相关文章

  1. SQL Server中参数化SQL写法遇到parameter sniff ,导致不合理执行计划重用的一种解决方案

    parameter sniff问题是重用其他参数生成的执行计划,导致当前参数采用该执行计划非最优化的现象.想必熟悉数据的同学都应该知道,产生parameter sniff最典型的问题就是使用了参数化的 ...

  2. 浅析SqlServer简单参数化模式下对sql语句自动参数化处理以及执行计划重用

    我们知道,SqlServer执行sql语句的时候,有一步是对sql进行编译以生成执行计划, 在生成执行计划之前会去缓存中查找执行计划 如果执行计划缓存中有对应的执行计划缓存,那么SqlServer就会 ...

  3. Sql Server之旅——第十一站 简单说说sqlserver的执行计划

    我们知道sql在底层的执行给我们上层人员开了一个窗口,那就是执行计划,有了执行计划之后,我们就清楚了那些烂sql是怎么执行的,这样 就可以方便的找到sql的缺陷和优化点. 一:执行计划生成过程 说到执 ...

  4. sqlserver的执行计划

    一:执行计划生成过程 说到执行计划,首先要知道的是执行计划大概生成的过程,这样就可以做到就心中有数了,下面我画下简图: 1. 分析过程 这三个比较容易理解,首先我们要保证sql的语法不能错误,sele ...

  5. SQLServer中的执行计划缓存由于长时间缓存对性能造成的干扰

    本文出处:http://www.cnblogs.com/wy123/p/7190785.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...

  6. MySQL— 索引,视图,触发器,函数,存储过程,执行计划,慢日志,分页性能

    一.索引,分页性能,执行计划,慢日志 (1)索引的种类,创建语句,名词补充(最左前缀匹配,覆盖索引,索引合并,局部索引等): import sys # http://www.cnblogs.com/w ...

  7. (转)explain、db2exfmt 命令的使用:文本输出执行计划

    原文:http://blog.51cto.com/freebile/1068610 db2有图形执行计划显示工具,如果没有图形环境,如unix主机,可以生成文本的文件来显示执行计划1.如果第一次执行, ...

  8. Sql Server中执行计划的缓存机制

    Sql查询过程 当执行一个Sql语句或者存储过程时, Sql Server的大致过程是 1. 对查询语句进行分析,将其生成逻辑单元,并进行基本的语法检查 2. 生成查询树(会将查询语句中所有操作转换为 ...

  9. ORACLE从共享池删除指定SQL的执行计划

    Oracle 11g在DBMS_SHARED_POOL包中引入了一个名为PURGE的新存储过程,用于从对象库缓存中刷新特定对象,例如游标,包,序列,触发器等.也就是说可以删除.清理特定SQL的执行计划 ...

随机推荐

  1. CentOS 上使用vscode 调试百度大数据分析框架Apache Doris BE

    A: 前期准备工作 1. 安装vscode,详细请参见vscode官网https://code.visualstudio.com/docs/setup/linux,摘要如下: sudo rpm --i ...

  2. CCproxy 设置代理服务器。

    CCproxy 设置代理服务器. 通过代理服务器上网,出口IP就固定成代理服务器的IP 设置安装比较简单,直接去ccproxy官网下载就行 如果服务器是公网服务器,记得在设置,高级里面的网络中,把禁止 ...

  3. linux记录每个用户执行的命令

    1.在/etc/profile中添加如下代码: #history USER_IP=`>/dev/null| awk '{print $NF}'|sed -e 's/[()]//g'` HISTD ...

  4. Thymeleaf系列五 迭代,if,switch语法

      1. 概述 这里介绍thymeleaf的编程语法,本节主要包括如下内容 迭代语法:th:each; iteration status 条件语法:th:if; th:unless switch语法: ...

  5. 传统项目利用Hystrix实现热点接口的服务隔离

    这段时间接了个需求,需要在我目前负责的数据系统上加个接口,主要是实现用户行为的记录.前端对接的项目主要有公司的PC,WAP,WEIXIN,APP等,每个端大概有两台左右的负载.因为目前我的这个项目主要 ...

  6. Excel2013复制内容粘贴到刷选的数据表中

    如何将复制内容粘贴到筛选后表格中: 1.需要一个表格:我要把这个表格里姓名列不包含A的项改为另外一个表中的数据列: 2.在姓名右侧插入两列,列A.列B: 3.在列A下第一格输入1,向下序列填充: 4. ...

  7. selenium webdriver——JS操作日历控件

    一般的日期控件都是input标签下弹出来的,如果使用webdriver 去设置日期, 1. 定位到该input 2. 使用sendKeys 方法 比如 但是,有的日期控件是readonly的 比如12 ...

  8. angularjs中的$http详解

    语法: 要将区别先弄清$http服务,它是对原生XMLHttpRequest对象的简单封装,是只能接受一个参数的方法, 这个方法会返回一个promise对象,具有sccess和error两个方法.当然 ...

  9. Rhythmk 一步一步学 JAVA (22) JAVA 网络编程

    1.获取主机信息 @Test public void GetDomainInfo() throws UnknownHostException { String domain = "www.b ...

  10. 迷你MVVM框架 avalonjs 0.98发布

    在本版本中,avalon侧重于对组件开发的支持,可用控件达到12个,末来将大力投入对GRID,TREE等重型UI的开发中. 添加ms-widget绑定,废弃ms-ui绑定 为ms-include添加跨 ...