T-SQL(Trantsact-SQL)是微软公司在SYBASE的基础上发展起来的一种结构化查询语言,是应用程序和存储过程与SQL SERVER通讯和访问的工具.包涵了ANSI89和ANSI92标准.所以T-SQL不是一种标准的编程语言,它必须通过SQL SERVER的数据引擎来分析和运行,SQL SERVER是如何编译和运行T-SQL语句呢?
SQL SERVER在处理任何T-SQL语句时都经过下面三个步骤:
1. 解析T-SQL语句
2. 编译T-SQL语句
3. 执行T-SQL语句
当一个T-SQL的批处理提交到SQL SERVER服务器,服务器回将这个T-SQL批处理作为一个整体进行分析,在优化,编译,最后在分步执行.
一. 解析
所谓”解析”是指SQL SERVER命令解析模块首先检查T-SQL批处理语法的过程,如果没有找到错误,命令解析器将源代码细分为多个逻辑单元,比如:关键字,标识符以及运算符.然后命令解析器会构建一个内部结构,最后通过这个内部结构生成DDL操作或DDM操作所需要的详细的步骤.如果该T-SQL批处理包涵一个查询,那么这个内部结构被成为查询树(QUERY TREE),如果该T-SQL批处理是一个过程,那么这个内部查询被成为顺序树(SEQUENCE TREE).
图一:SQL SERVER的关系引擎部分
大家可以看出在图一的左边,主要是T-SQL的解析,编译和查询优化(Query Optimizer).这是SQL SERVER运行T-SQL非常关键的部分.在图的右边是执行组件,当T-SQL语句编译过后就会直接传给执行结构进行运行.在中间的部分是SQL管理器,控制整个T-SQL批处理的解析,编译和执行. SQL Message 是从客户端接受的(TDS)数据.Express Services Libary是进行数据转换,过虑数据和进行计算和统计,同时也会格式化输出的数据.
二.编译
这一步主要是将顺序树(SEQUENCE TREE)生成为一个执行规划, 查询优化器(Query Optimizer)主要是对T-SQL语句所要检索的资源进行评估,生成I/O的时间,过虑时间和其他逻辑处理的时间.然后查询优化器(Query Optimizer)是试图利用一个最小资源的方案.
这个方案中还包括执行是需要的任务列表(比如:安全检查,约束检查,触发器检查等等).这个就被成为执行规划
三.执行
执行组件根据执行规划在高速缓存中运行并滞留,执行规划的不同步骤将被发送到关系引擎的不同组件进行处理:DML管理器,DDL管理器,存储过程管理器,事务处理管理器和实用工具管理器.处理结果将以结果集的方式被收集合并返回调用者.
执行规划将在高速缓存中被保留一段时间,如果同一用户或其他用户发出类似请求的T-SQL批处理,关系数据引擎将会优先在高速缓存中寻找匹配的执行规划.如果该执行规划存在就采用运行,如果不存在,SQL SERVER 就会解析并编译这个T-SQL批处理.
如果SQL SERVER需要的内存不够,它会从内存中删除一些执行规划.SQL SERVER有一个很好的”老化”算法,它可以统计某个执行规划的使用时间和次数.如果内存足够的大,也可以无限的增加执行规划到内存中.
四. 简单查询执行规划的重用
简单T-SQL批处理只可以在2中情况下被重用:
1. 第二次查询的文本必须和高速缓存中执行规划所描述的文本完全相同,每一项都要匹配,包括:空格,换行,缩排,在大小写敏感的SQL SERVER中还包括字符的大小写.
2. 查询包涵完全修饰的数据库对象以便重用执行规划.
SELECT * FORM PUBS.DBO.SALES
所以在这种情况下:”*” 的执行效率要高于SELECT COLUMN_LIST FROM TABLENAME的语句.
五.存储过程执行规划的重用:
存储过程比简单查询执行效率高的一个主要原因是:存储过程的执行规划可以方便的被重用.比图:在执行一个简单查询3次,那么SQL SERVER需要执行3次解析—编译—执行的过程,而存储过程最有可能的是在第一次执行之前被解析并被重新编译一次.
存储过程的执行规划分2部分:
1. 可重入部分,可以被人员数量的存储过程同时使用;
2. 包括数据上下文的部分,也就是执行期间存储过程的各个参数;
在SQL SERVER中有一个组件--惰性写入器(LAZYWRITER),来判断缓存中的执行规划是否会重用和是否需要申请更多的内存.如果有下列的操作,SQL SERVER将立即重缓存中删除执行规划,释放内存:
l 明显改变数据量;
l 创建和删除INDEX;
l 添加和更改约束;
l 更改INDEX的分布信息;
l 显示的调用sp_recompile以重新编译存储过程或触发器;
当SQL SERVER建立一个执行规划就会给该执行规划一个”编译成本因子”.这个成本因子的值取决于创建该执行规划所需要的资源开销.例如:赋予一个大型的执行规划的编译成本因子是8,而一个小的执行规划的编译成本因子是2.每次某个CLIENT引用该执行规划,他的”年龄”就会递增一个编译成本因子的值.
SQL SERVER的惰性写入器(LAZYWRITER)是如何工作的呢? SQL SERVER的惰性写入器用来降低执行规划的”年龄”, 惰性写入器进程会定期循环遍历高速缓存中的所有执行规划,并将执行规划的”年龄”减1,当执行规划的编译成本因子的值为0时,SQL SERVER就会收回分配给该执行规划的内存.
备注:
SQL SERVER的优化组件(Query Optimizer)会在存储过程引用的表数据更新时自动重新编译该存储过程,更新执行规划.但在你添加一个INDEX时,SQL SERVER不会自动重新编译存储过程,需要手动刷新高速缓存的执行规划(最简单的方法,你可以重新启动MSSQLSERVER服务),这是该存储过程会被重新编译,或者你可以手动强制重新编译:
Exec sp_recompile sp_storedprocedurename
SQL SERVER还提供了另外一种高效的重新编译的方法:如果有大量的存储过程和触发器引用某一个表,并且还添加表INDEX以提高检索的效率.这是我们可以通过重新编译这个表来重新编译所有的存储过程和触发器:
EXEC sp_compile tablename.
所有我们在重新建立索引或执行了更新索引的操作子后,一定要重新编译存储过程,不过这是最好的办法是重新启动服务器.