浅析SqlServer简单参数化模式下对sql语句自动参数化处理以及执行计划重用
我们知道,SqlServer执行sql语句的时候,有一步是对sql进行编译以生成执行计划,
在生成执行计划之前会去缓存中查找执行计划
如果执行计划缓存中有对应的执行计划缓存,那么SqlServer就会重用这个执行计划缓存,避免编译,从而提高效率,
对于开发者来说,为了达到能够重用执行计划的目的,使用参数化的sql是一个必要的条件。
除了参数化的sql,对于即席查询或者是动态生成的查询语句,也就是非参数化的sql语句,SqlServer本身也在对一些sql进行自动优化处理。
在SqlServer层面,分为简单参数化和强制参数化两种方式,SqlServer数据库中对sql的解析方式,默认是简单参数化,当然也可以设置为强制参数化。
在简单参数化模式下,SqlServer对查询有一些专门的优化,就是sql查询条件一些变量的值,不会影响到查询的执行计划,
那么SqlServer会自动地进行参数化处理,后续如果有类似的查询,可以使用自动参数化的sql生成的执行计划,避免重编译,从而提高sql的执行效率以及减少服务器资源的消耗。
参数化的设置是一个数据库级别的选项,如下是通过图形界面看到的参数化默认设置方式,默认是“简单”模式,也可以设置为“强制”模式,
也可以通过脚本的方式来设置
1
2
3
4
5
6
|
--查看数据库的参数化方式
select name ,is_parameterization_forced from sys.databases where name = 'dbtest'
--默认是简单模式
alter database dbtest set parameterization simple
--可以设置为强制模式
alter database dbtest set parameterization forced
|
首选来看简单参数化模式下的处理方式
这种情况下,如果一个查询的常量值不影响执行计划的方式,那么SqlServer会对这个查询生成一个参数化的sql,随后的查询中的即便常量的值发生了变化,也会重用上面进行参数化后生成的执行计划,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
create table t_1
(
id int ,
name varchar (50)
)
insert into t_1 values (1, 'A' )
insert into t_1 values (2, 'B' )
insert into t_1 values (3, 'C' )
insert into t_1 values (4, 'D' )
insert into t_1 values (5, 'E' )
--测试之前注意清空一下执行计划缓存
dbcc freeproccache
|
首选执行第一个查询
select * from t_1 where id=1
执行完成后,我们查询执行计划中的信息
1
2
3
4
5
|
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%'
|
此时会观察到,
select * from t1 where id=1这一句sql本身也被缓存了,同时自动生成了一个objtype为prepared的执行计划,
此时再执行另外一个sql:select * from t1 where id=2
注意观察参数objtype为prepared的执行计划的usecounts,由第一次的1变为了2
说明第二句执行的sql重用了第一句sql自动参数化生成的执行计划,第一次自动参数化生成的执行计划得到了重用。
或许你会有一点疑问,第二个执行的sql也就是select * from t_1 where id=2
也生成了执行计划,为什么说这一句sql执行的时候重用了第一句sql生成的执行计划的缓存的呢?
这里会看到,执行的原始的sql语句生成的执行计划的类型都是Adhoc的,这种执行计划称之为壳查询(Shell Query),
(这里解释一下,Adhoc查询很多人称之为即席查询,但是这里类型是Adhoc查询,却不是即席查询,
即席查询时包含完整的执行计划的,这里的壳查询时不包含执行计划的,只能说所谓的即席查询是Adhoc类型的查询的一种
上面查询执行计划的sql再加一个DMV,如下,就会发现,生成的Adho执行计划缓存中q.query_plan为空,并不包含完整的执行计划
select usecounts,size_in_bytes,objtype,t.text ,q.query_plan from sys.dm_exec_cached_plans p cross apply sys.dm_exec_sql_text(p.plan_handle) t cross apply sys.dm_exec_query_plan(p.plan_handle) q where p.cacheobjtype='Compiled Plan' and t.text like '%t_1%' and t.text not like '%dm_exec_cached_plans%')
这个壳查询也会缓存,但是其未包含完整的执行计划,只包含sql的文本以及执行真正执行计划的指针,
缓存壳查询的目的在于当执行与壳查询完全相同的sql时,查询语句可以快速地找到其对应的真正的执行计划
缓存壳查询的目的在于:
用户发送给SqlServer的是一个文本,因为可能每次查询条件不同,文本本身也是不同的,SqlServer缓存的是一个参数化的执行计划,如果用户发送过来的文本匹配上了壳查询,壳查询又存储了一个指向真正执行计划的指针,那么就可以将用户发送过来的sql快速连接到其执行计划,是作为连接用户发送过来的sql和自动参数化生成的执行计划的一道桥梁。另外,缓存壳查询因为没有包含完整的执行计划,所以其占用的内存也并没有一个完整的执行计划占用的内存大,
从size_in_bytes字段也可以看到,壳查询的缓存的空间是没有参数化的sql的占用空间大的。
在执行select * from t_1 where id=1之后,生成了参数化的执行计划,
随后如果多次执行select * from t_1 where id=2,会发现参数化后的执行计划usecounts并没有增加,一直为2,而壳查询的计划的usecounts在增加,
上面说了,“缓存壳查询的目的在于当执行与壳查询完全相同的sql时,查询语句可以快速地找到其对应的真正的执行计划”,
此时虽然真正使用的是参数化执行计划,但是DMV中只是将壳查询的usecounts计数器加1
那么回头再想一个问题,对于简单参数模式下,SqlServer什么情况下回对sql语句自动参数化?
简单模式下,SqlServer并不是所有的sql都进行参数化处理,只有对那些有且只有一种执行计划的sql语句,才自动参数化处理,
比如上面的查询,因为t_1表上的id列上没有任何索引,不管对于任何一个值,都只能是全表扫描的方式去执行这个查询,此时SqlServer会做到自动参数化,生成一个可重用的执行计划。
如果id列上有一个非唯一的索引,那么select * from t_1 where id=***这个查询就有可能存在不同的执行计划,
比如是索引查询或者是全表扫描,这个要依据列上的统计信息了(这个话题也比较大,就不展开说了),
也就是说,在不同的查询条件下,有可能生成不同的执行计划,那么SqlServer就不会为其生成参数化的sql。
比如在id列上见一个非唯一的索引,那么再次观察执行计划缓存,就发现SqlServer并没有生成一个自动参数化的执行计划。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
--测试之前注意清空一下执行计划缓存
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指令,提高执行效率的目的。
浅析SqlServer简单参数化模式下对sql语句自动参数化处理以及执行计划重用相关推荐
- 一条sql语句在mysql中如何执行的
文心阁小说本篇文章会分析下一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的. 在分析之前我会先带着你看看 MySQL ...
- 在单用户模式下启动SQL Server的不同方法
In this article, we will review different ways to start SQL Server in single user mode. 在本文中,我们将介绍在单 ...
- 浅析PowerBuilder下动态SQL语句
作者:张继荣 王举国 谭琦 谢元呈 PowerBuilder是目前最流行的数据库开发工具之一.PowerBuilder提供了在程序代码中加入嵌入式SQL语句的功能来支持对数据库的访问.但这种嵌入式SQ ...
- SQLserver获取所有表及结构SQL语句
SQLserver获取所有表及结构SQL语句 SELECT 表名 = CASE WHEN A.COLORDER=1 THEN D.NAME ELSE '' END, 表说明 = CASE WHEN A ...
- SQL点滴27—性能分析之执行计划
一直想找一些关于SQL语句性能调试的权威参考,但是有参考未必就能够做好调试的工作.我深信实践中得到的经验是最珍贵的,书本知识只是一个引导.本篇来源于<Inside Microsoft SQL S ...
- RDS SQL Server - 专题分享 - 巧用执行计划缓存之Table Scan
背景引入 执行计划中的Table Scan或者是Clustered Index Scan会导致非常低下的查询性能,尤其是对于大表或者超大表.执行计划缓存是SQL Server内存管理中非常重要的特性, ...
- SQL Server性能调优之执行计划深度剖析 第二节 执行计划第一次实践
SQL Server性能调优之执行计划深度剖析 第二节 执行计划第一次实践 前言:自从上一篇文章发出之后,收到了很朋友的关注.很多朋友要求多多实践,而不是纯粹的理论.确实,从打算出这个系列开始,我就本 ...
- 如何在SQL Server 2016中比较查询执行计划
SQL Server 2016 provides great enhancement capability features for troubleshooting purposes. Some of ...
- powerdesigner生成php代码,让powerdesigner生成的sql语句在mysql上成功执行
花了大概半天的时间学习了下powerdesigner的用法,等我生成sql语句时,发现在生成的sql语句根本不能在mysql中执行,当然我的dbms是设置了mysql的. 在网上搜索一通,也没有什么好 ...
- sql语句跨服务器跨数据库执行
加为好友 发送私信 在线聊天 wuyi8808 空军 等级: 可用分等级:富农 总技术分:47189 总技术分排名:187 发表于:2009-04-15 21:38:422楼 得分:0 sql语句跨服 ...
最新文章
- Python模块之间的相互引用问题
- 用一张图片告诉你芯片设计
- SpringSecurity AuthenticationManagerProviderManager
- eclipse 3.7 search 报resource is out of sync with the file system 解决方法
- python编程入门指南-最简单的Python编程入门指南,没基础也能快速入门Python编程...
- 书单丨成为全栈工程师的5种硬实力
- JS正则表达式从入门到入土(7)—— 分组
- Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]
- CentOS-6.3安装配置Tomcat-7
- 【牛客小白赛12:J/2019南昌网络赛:M/牛客练习赛23:D】查询字符串ss是否是字符串s的子序列(序列自动机裸题)
- 快速搭建pgadmin4环境
- kali linux 安装谷歌浏览器
- 计算机应用程序没声音怎么办,电脑没声音怎么办
- 教育大数据可视化研究综述笔记
- Zigbee Zstack2.5.1a使用rfx2401+cc2530
- linux下编译C++项目
- Springcloud的版本依赖问题(最全,包含springCloud所有的版本)
- 把时间当作朋友 -- 读书笔记
- 用python计算圆周率_用python计算圆周率π
- 网站建设(一)PHP深入学习
热门文章
- 计算机专业c类大学,【计算机应用技术】专业排名A+、A、B+、B、C类院校分数线...
- 学数值计算可以从事计算机算法吗,数值计算方法
- java基于http协议编程_网络传输协议(http协议)
- c++ opencv mat_【CV实战】OpenCV—Hello world代码示例
- rep( )函数--R语言
- text函数--Matplotlib
- MacbookPro添加硬盘内存
- 在克隆环境上分离httpd和subversion。
- Android --- GreenDao的实现(ORM框架)
- ubuntu下弹框提醒