Oracle中,为了减少系统内的硬解析,从而节省系统资源,有绑定变量、计划共享(通过cursor_sharing参数)等一系列措施。那么,SQL Server作为三大商业关系库之一,是否也存在这样的机制呢?答案是肯定的,下面,我们就一起来看看SQL Server系统中的类似机制。

SQL Server主要通过如下四个机制来缓冲之前执行过的查询的执行计划,以避免这些查询的再次编译,从而节省系统资源。

1)临时查询缓冲(Ad hoc query caching);

2)自动参数化(parameterize automatically);

3)准备查询(prepared queries);

4)编译对象(compiled objects);

下面,分别对SQL Server着四个机制介绍如下:

1)临时查询缓冲

SQL Server2005以前,临时计划偶尔也会被缓冲,但是我们不能指望这个特性发挥太多效果。即使后续版本中,当SQL Server缓冲临时计划时,被缓冲的这些计划也只有在随后的批处理文本和这些计划的文本完全匹配时,才能被重用。我们可以通过如下SQL语句来查询被缓冲的临时查询计划的被重用情况:

SELECT usecounts, cacheobjtype, objtype, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype = 'Compiled Plan'
AND [text] NOT LIKE '%dm_exec_cached_plans%';

为了改善被缓冲的临时查询计划重用状况不佳的问题,SQL Server提供了一种特性,称之为临时负载优化选项(Optimize for Ad Hoc Workloads option),我们可以通过如下方式开启它:

EXEC sp_configure 'optimize for ad hoc workloads', 1;
RECONFIGURE;

GO

你也可以通过SQL Server management studio中服务器属性的高级页面开启这个特性。该特性被打开后,相同的临时查询第一次被编译时,会在计划缓冲中产生该语句的编译计划根(compiled plan stub),该计划根所占内存空间不会超过300个字节,包含指向该查询文本的指针。当该查询再次被编译时,被缓冲的计划根会被编译计划代替,而该编译计划比原来的计划根要大很多,要占用两个页大小的内存空间。

可以通过如下查询获取该特性开启后,被缓冲的编译计划根和编译计划的信息:

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype LIKE 'Compiled Plan%'
AND [text] NOT LIKE '%dm_exec_cached_plans%';

该特性开启后,还可以通过如下命令关闭:

EXEC sp_configure 'optimize for ad hoc workloads', 0;
RECONFIGURE;
GO

也可以通过SQL Server management studio中服务器属性的高级页面关闭该特性。

2)自动参数化

说到参数化,SQL Server又将其分为简单参数化(Simple parameterization)和强制参数化(Forced parameterization)两种情形。这有点类似Oracle中的cursor_sharing参数的使用。下面,我们就先说说简单参数化,简单参数化也是SQL Server的默认设置和行为。有时,SQL Server会地自动将查询中的常数参数化,随后的查询如果和参数化后的查询语句一样,将会重用之前参数化查询的缓冲的执行计划。同样,我们也可以通过如下语句对参数化的行为进行查询和分析:

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype = 'Compiled Plan'
AND [text] NOT LIKE '%dm_exec_cached_plans%';
GO

结果中,针对每个带常数的查询,会产生一个被缓冲的编译计划,这些临时查询作为壳查询(shell query)的编译计划被缓冲,目的就是为了后续相同常数查询发现查询的参数化版本更容易些,这些常数查询被缓冲的编译计划占用内存空间较小,大概为两个页大小,也并不包含完全的编译计划。而针对所有这些常数查询,系统也会生成一个参数化的查询,该查询称为准备查询(prepared query),这个准备查询的编译计划才是完整的编译计划,因此,占用内存空间也会更大些,大概为四个页大小。

说完了简单参数化,下面,我们说说强制参数化。

有时,你的应用用了很多类似的语句,而且,你认为可能会从编译计划重用中获益,但遗憾的是,系统并不能将这些类似的语句参数化。此时,SQL Server提供了一个数据库选项,那就是PARAMETERIZATION FORCED,可通过如下命令对该选项进行设置:

ALTER DATABASE <database_name> SET PARAMETERIZATION FORCED;

设置该选项后,SQL Server就会将相关查询中常数参数化,但也会有些例外,具体可查询微软官方或其他文档。值得注意的是,这种为了重用缓冲编译计划,将查询中常数一概参数化的做法,有时也可能会带来严重的性能问题,因此,实际应用时,一定要具体问题具体分析。

3)准备查询

如上所述,SQL Server参数化的查询可以在计划缓冲区中生成准备查询类型的编译计划。此外,另外两种方法也可以生成准备查询类型的编译计划。但是,他们和SQL Server参数化的查询不同,这两种方法中用户可以自己决定参数的数据类型。其一是通过T-SQL批处理调用sp_executesql内置过程;其二是通过客户端应用使用准备和执行方法。这两种方法,有点类似Oracle中的绑定变量使用。

sp_executesql过程:使用该过程要求用户确定参数和它们的数据类型,具体语法如下所示:

sp_executesql @batch_text, @batch_parameter_definitions,param1,...paramN

只要通过相同@batch_test和@batch_parameter_definitions参数值调用该过程,就会重用缓冲中的统一编译计划。例如:

EXEC sp_executesql N'SELECT c2, c3, c4 FROM test.t1 WHERE c1 = @p', N'@p int', 1;

EXEC sp_executesql N'SELECT c2, c3, c4 FROM test.t1 WHERE c1 = @p', N'@p int', 2;

EXEC sp_executesql N'SELECT c2, c3, c4 FROM test.t1 WHERE c1 = @p', N'@p int', 3;

准备和执行方法:该方法和sp_executesql过程类似,但不尽相同。该方法并不需要运行时每次都要传送全部批命令文本,而是,只要在准备阶段传送一次即可,然后,返回的句柄可供每次运行批命令时使用。然而,该方法会在计划缓存区生成准备查询的编译计划,但并不会生成类似自动参数化中相应的临时壳查询计划。同样,我们可以通过如下查询获取编译计划相关信息:

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype = 'Compiled Plan'
AND [text] NOT LIKE '%dm_exec_cached_plans%';
GO

4)编译对象

计划缓存区中,除了包含之前讲到的临时查询编译计划和准备查询的编译计划,还包含第三种编译计划,那就是过程类型(PROC),该类型计划主要由存储过程、用户定义的标量函数和多语句表值函数等,用户可以完全控制这些对象参数的值和类型。这些对象的成功执行,都会重用计划缓存的之前运行的相同对象的编译计划。然而,用户也可以通过选项或重建,来强制这类对象生成新的编译计划,例如:

--存储过程

EXEC P_Test  'EM';
GO
EXEC P_Test  'IN';
GO
EXEC P_Test  'IN' WITH RECOMPILE;

--函数

DECLARE @p1 char(11);
EXEC @p1= test. f_test '123456789';
SELECT @p1;
GO
DECLARE @p1 char(11);
EXEC @p1 = test. f_test '987654321';
SELECT @p1;
GO
DECLARE @p1(11);
EXEC @p1 = test.f_test '987612345' WITH RECOMPILE;

同样,我们可以通过如下查询语句获取编译计划相关信息:

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype = 'Compiled Plan'
AND [text] NOT LIKE '%dm_exec_cached_plans%';
GO

MSSQL优化(TUNING & OPTMIZATION & 优化)之——计划重用(plan reusing)的更多相关文章

  1. PLSQL_性能优化系列16_Oracle Tuning Analyze优化分析

    2014-12-23 Created By BaoXinjian

  2. oracle11g中SQL优化(SQL TUNING)新特性之SQL Plan Management(SPM)

    1.   简介 Oracle Database11gR1引进了SQL PlanManagement(简称SPM),一套允许DBA捕获和保持任意SQL语句执行计划最优的新工具,这样,限制了刷新优化器统计 ...

  3. MSSQL数据库 1000W数据优化整理

    GO SET STATISTICS TIME ON SELECT count([StyleId]) FROM [dbo].[Ky_Style] SET STATISTICS TIME OFF SET ...

  4. SQL优化笔记—CPU优化

    补充:常规服务器动态管理对象包括,下面有些资料可能会应用到 dm_db_*:数据库和数据库对象dm_exec_*:执行用户代码和关联的连接dm_os_*:内存.锁定和时间安排dm_tran_*:事务和 ...

  5. 使用SQL Profile及SQL Tuning Advisor固定运行计划

    SQL Profile就是为某一SQL语句提供除了系统统计信息.对象(表和索引等)统计信息之外的其它信息,比方执行环境.额外的更准确的统计信息,以帮助优化器为SQL语句选择更适合的执行计划. SQL ...

  6. android:布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!

    1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayo ...

  7. 数据库的优化(表优化和sql语句优化)

    在这里主要是分为表设计优化和sql语句优化两方面来实现. 首先的是表设计优化: 1.数据行的长度不要超过8020字节.如果是超过这个长度的话这条数据会占用两行,减低查询的效率. 2.能用数字类型就不要 ...

  8. Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构(源码可下载)

    Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构(源码可下载) 说明:Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构,我采用以下三种维度来讲解 1.  代码层面. 2.  数 ...

  9. Android为TV端助力 布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!

    1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayo ...

随机推荐

  1. Shell 脚本批量创建数据库表

    使用 Shell 脚本批量创建数据表 系统:Centos6.5 64位 MySQL版本:5.1.73 比如下面这个脚本: #!/bin/bash #批量新建数据表 for y in {0..199}; ...

  2. Linux 命令之mv

    mv命令也是Linux中很常见命令 作用:可以用来移动文件或者将文件改名 命令格式: mv [选项] 源文件或目录 目标文件或目录 命令参数: -b :若需覆盖文件,则覆盖前先行备份. -f :for ...

  3. 无法获取未定义或 null 引用的属性“contentWindow”

    在iframe 中有时候 这样使用contentWindow 会报   无法获取未定义或 null 引用的属性“contentWindow”   这种情况 我是在IE中遇到 其他浏览器一切正常. pa ...

  4. 前端性能优化之按需加载(React-router+webpack)

    一.什么是按需加载 和异步加载script的目的一样(异步加载script的方法),按需加载/代码切割也可以解决首屏加载的速度. 什么时候需要按需加载 如果是大文件,使用按需加载就十分合适.比如一个近 ...

  5. EDCheckPrefabRef

    using UnityEngine;using System.Collections;using UnityEditor;using UnityEngine.UI;using System.Refle ...

  6. 蚂蚁金服×西安银行 | 西安银行手机银行App的智能升级之路

    小蚂蚁说: 当前,数字化信号已经逐渐深入到社会的每个角落,影响着用户的心智和行为,来到数字化时代门口的银行,需要注意到数字化信号.西安银行通过引入蚂蚁金服移动开发平台mPaaS,对手机银行进行架构升级 ...

  7. 关于git提示“warning: LF will be replaced by CRLF”终极解答

    一.发现问题 windows平台下使用git add,git deploy 文件时经常出现“warning: LF will be replaced by CRLF” 的提示. 网上很多解决办法提到: ...

  8. gc调优我们到底在调整什么

    java开发一般都会涉及到jvm调优其中gc调优是个重点项.那gc调优调整的究竟是什么呢准确来说是业务.下面围绕这个话题展开 起因 为什么说是业务呢得从cc++开始说起如果说是用c/c++做开发运行的 ...

  9. 力扣(LeetCode)728. 自除数

    自除数 是指可以被它包含的每一位数除尽的数. 例如,128 是一个自除数,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0. 还有,自除数不允许包含 0 . 给定上边 ...

  10. python实现邮件接口——smtplib模块

    1. 思路 使用脚本发送邮件的思路其实和客户端发送邮件一样,过程都是: 登录 —> 写邮件 —> 发送 只不过通过脚本发送时我们需要考虑到整个过程的方方面面.以下为思路导图: 2. Pyt ...