热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

SqlServer编译、重编译与执行计划重用原理(转)

当SqlServer收到任何一个指令,包括:查询、批处理、存储过程、触发器、预编译指令和动态SQLServer语句,要完成语法解析、语义分析,然后再进行编译,生成能够运行的执行计划。在编译的过程中,SQLServer会根据所涉及的对象的架构、统计

当 Sql Server 收到任何一个指令,包括:查询、批处理、存储过程、触发器、预 编译 指令和动态SQL Server语句,要完成语法解析、语义分析,然后再进行" 编译 ",生成能够运行的" 执行 计划 "。在 编译 的过程中,SQL Server 会根据所涉及的对象的架构、统计

当 Sql Server 收到任何一个指令,包括:查询、批处理、存储过程、触发器、预编译指令和动态SQL Server语句,要完成语法解析、语义分析,然后再进行"编译",生成能够运行的"执行计划"。在编译的过程中,SQL Server 会根据所涉及的对象的架构、统计信息,以及指令的具体内容,估算可能的执行计划,以及它们的成本,最后选择一个SQL Server认为成本最低的语句。

执行计划生成之后,SQL Server 通常会把它们缓存到内存里,术语统称它们叫"Plan Cache"。以后同样的语句执行,SQL Server就可以使用同样的执行计划,而无须再做一次编译。这种行为,叫做“重用”。但是有时候,哪怕是一模一样的语句,SQL Server 下次执行还是要再做一次编译。这种行为叫“重编译”。执行计划编译和重编译都是要耗费资源的。

执行计划的好坏当然决定了语句的执行速度。对于同样一条语句,使用好的执行计划可能会比差的要快几百倍,甚至几千倍。所以从这一角度上来讲,没运行一条语句,都把它先编译一遍当然是最好的。它能够保证使用的执行计划是 SQL Server 能找到的最优的。但是 SQL Server 每秒钟可能会运行成百上千的指令。如果每个都编译一遍,是资源的严重浪费。所以 SQL Server 在这里也试图寻找一个平衡点,使用优先的 complie/recomplie,得到最好的整体性能。

查看 SQL Server 缓存的执行计划,可以运行下面这条语句:select * from sys.syscacheobjects

对不同的指令调用方法, SQL Server 做执行计划缓存和重用机制也有所不同。下面介绍最常见的几种:

1. Adhoc 语句

一组包含 Select、Insert、Update、Delete 的批处理指令。对这样的指令,只有前后完全一直,包括字母的大小写、空格、回车换行都一致, SQL Server 才认为是两条一样的语句,才能够重用执行计划。所以这个要求还是挺高的。

2. 用 Exec() 的方式运行动态 SQL Server 语句

有些应用程序为了开发上的灵活程度,在程序运行过程中,动态地拼接成一个语句字符串,然后用 Exec() 的方式执行。这种调用方法被称为"dynamic SQL"。它的好处就是很灵活,可以根据客户的选择,动态生成指令,而不仅限于预定义的那几种。但是它的缺点也是太灵活了,客户发过来的语句每次都不一样,或者语句主体部分是一样的,但是参数不一样, SQL Server 都要做编译。这点和 adhoc 语句是一样的。

3. 自动参数化查询

对于一些比较简单的查询, SQL Server 2005 自己就可以做自动参数化,把语句里的参数用一个变量代替,但是这仅限于很简单的查询。

4. 用 sp_executesql 的方式调用的指令

查询自动参数化在很多种条件下是不支持的,而且它还是要为每句查询生成一个 adhoc 的执行计划。所以它并不是减少比哪一的最有手段。改用 sp_executesql 能够更有效地增加执行计划重用

5. 存储过程

对用户经常要调用的指令,把他们做成存储过程,既方便管理、规范脚本,又能够大大提高执行计划调用,是值得推荐的一种做法。从 SQL Server 的角度,最好绝大多数指令都能够以存储过程的方式调用,尽量少使用 Dynamic SQL 的方式。

但是有些时候, SQL Server 为了确保返回正确的值,或者有性能上的顾虑,有意不重用缓存在内存里的执行计划,而现场编译一份。这种行为,被成为重编译。下面是比较常见的会发生重编译的情形:

1. 当指令或批处理所涉及的任何一个对象(表格或者试图)发生了架构(schema)变化

例如,在表或者视图上添加或删除另一个字段、添加或删除了一个索引,在表上添加或者删除了一个约束条件等。定义发生了变化,原来的执行计划就不一定正确了,当然要重编译

2. 运行过 sp_recomplie 后

当用户在某个存储过程或者触发器上运行过 sp_recomplie 后,下一次运行它们就会发生一次重编译。如果用户在某个表或试图上运行了 sp_recomplie ,那么所有引用到这张表或视图的存储过程在下一次运行前,都要做重编译

3. 有些动作会清除内存里的所有执行计划,迫使大家都要做重编译

Detach 一个数据库

对数据库做了一个升级,在新的服务器上会发生执行计划清空

运行了 DBCC FreeProccache 语句

运行了 ReConfigure 语句

运行了 Alter DataBase ... Modify FileGroup 语句

用 Alter DataBase ... Collate 语句修改了某个数据库的字符集

下列动作会清除 SQL Server 服务器缓存的某个数据库的执行计划

DBCC FlushProcinDB 语句

Alter DataBase ... Modify Name 语句

Alter DataBase ... Set Online 语句

Alter DataBase ... Set Offline 语句

Alter DataBase ... Set EmerGency 语句

Drop DataBase 语句

当一个数据库自动关闭时

DBCC CheckDB 语句结束时

4. 当一些 Set 开关值变化后,先前的那些执行计划都不能重用

5. 当表格或试图上的统计信息发生变化后

当统计信息被手动更新后,或者 SQL Server 发现某个统计信息需要自动更新时, SQL Server 会对所涉及的语句都做重编译

须说明的是,在 Sql Server 里,执行计划重用并不一定是一件好事,而编译编译也不一定是一件坏事。在 Sql Server 里,能对计划重用编译/重编译产生影响的功能主要有:

1. 使用存储过程,或者 sp_executesql 的方式调用会被重复使用的语句,而不要直接用 ad-hoc 语句或者 dynamic SQL 。

2. 在语句里引用对象(表、视图、存储过程等),到带上它的 schema 名字,而不光是对象自己的名字。

3. 将 数据库IsParameterizationForced属性设置成TRUE

这个属性是开启数据库强制参数化。也就是说,对于在这个数据库下运行的大部分语句,SQL Server 都会先参数化,再运行。如果应用经常用 adhoc 的方式调用一样的语句,强制参数化可能会有所帮助

4. 统计信息更新

统计信息手工或者自动更新后,对和它有关的执行计划都不再能重用,而会产生重编译

5. Create Procedure ... with Recompile 选项 和 Exce ... with Recomplie 选项

在重建或者调用存储过程的时候使用 "with Recomplie",会强制 Sql Server 在调用这个存储过程的时候,永远都要先编译,再运行。

6. 用户使用了 sp_recomplie

7. 用户在调用语句的时候,使用了 "Keep Plan" 或者 "KeepFixed Plan" 这样的查询提示

转载地址:http://blog.csdn.net/babauyang/article/details/7714211



来自为知笔记(Wiz)

推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了如何找到并终止在8080端口上运行的进程的方法,通过使用终端命令lsof -i :8080可以获取在该端口上运行的所有进程的输出,并使用kill命令终止指定进程的运行。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
author-avatar
萌星
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有