第一章:执行计划基本知识

      简单地说,执行计划是查询优化器以最有效的方式来完成用户提交的T-SQL查询请求的结果。

通过执行计划,可以让你了解一条查询是如何执行,因此,对于众多DBA来说,解决性能较慢的查询主要目标就是了解查询计划的工作原理,而不是猜测特定的查询执行了上千次扫描。你可以使用执行计划来找出导致性能问题的完整SQL代码片断,例如:可能是由于扫描整张表,然而只需要的行,所有的这些都可以在执行计划中找到。

    本章的目的是帮助你来捕获实际和估计的执行计划,可以通过图形、文本或XML格式来描述它们的工作原理,本章先介绍以下几个主题:

  • l 查询优化器的简单背景
  • 执行计划是优化器的产物,因此对于了解其工作内容和运行机制很有帮助。
  • l 实际执行计划与估计执行计划
  • l 捕获并解释可视化执行计划的区别
  • l 自动化捕获执行计划:使用SQL Server Profiler工具

1.1 查询提交时发生了什么?

      当提交一条查询给SQL Server数据库时,服务器需要一系列的进程来运行查询,所有这些进程的主要工作是管理这样一个如提供数据的存储、维护数据的完整性的系统。

      提交给SQLServer的每一条查询都由这些进程来处理,同时在SQL Server内则有许多不同操作发生。这里主要专注于T-SQL范围的进程处理,大体可以划分以下两个阶段:

l发生在关系引擎中的进程

l发生在存储引擎中的进程

     在关系引擎中,查询首先解析,然后转由查询优化器来处理,从而生成一条执行计划,接着该计划以二进制的形式发送给存储引擎,存储引擎用于获取或更新底层的数据。存储引擎主要负责诸如锁、索引维护、事务处理的工作。由于执行计划是关系引擎中产生,因此是需要研究的重点。

1.1.1查询解析

当提交一条T-SQL查询到SQL Server时,首先要经过关系引擎。

注:T-SQL查询可以是从命令行(cmd)执行的一条ad hoc查询,也可以是存储过程执行的数

请求,也可能是单批中的任何T-SQL语句或位于GO之间的多个T-SQL语句。

      一旦收到T-SQL时,首先通过一系列的语法检查,此步称之为查询解析,解析的结果以解析树的形式输出,该树描述了执行该请求的执行查询的逻辑步骤。

     如果该T-SQL操作不是一个DML语句,则该T-SQL不做优化处理,例如:对于SQLServer而言,创建表(Create Table)并没有提高性能的处理。若T-SQL串是一个DML语句,该解析树则由algebrizer进程来处理,algebrizer负责不同对象(表、列以及查询串中引用的其它对象)的解析。像类型标识符(varchar(50)与nvarchar(25))。诸如GROUP BY和MAX这样的聚合函数也需要由algebrizer来决定在查询树的位置。

Algebrizer则输出一个格式为二进制的查询树,进而递交给查询优化器。

1.1.2查询优化器

      查询优化器基本上是关系引擎工作抽象的一个软件模型,通过使用查询树和包含数据的统计信息,然后应用该模型,从而以最优的方式来执行该查询,也就是产生一条执行计划。

      换句话说,优化器计算出实现T-SQL查询提交请求的最佳方法,可以根据访问的数据是否通过索引、连接的类型或其它更多的信息来判断。查询优化器采取的方法主要基于给定执行计划的开销,如需要处理的CPU和I/O资源,也就是“基于开销”的计划。

      查询优化器产生并估算许多计划,一般来说,选取最低开销的计划,也就是执行最快消耗最少CPU和I/O资源的计划。由于执行速度的计算是最重要的计算,因此查询优化器则采用更为精确的CPU运算进程以便返回的结果更快。

      如果提交一条简单的查询,如:没有索引、聚合或计算的单表,而不需要花过多时间来计算可优的计划,查询优化器则简化选取一个普通计划。

     如果该查询并不是普通的计划,查询优化器则根据开销计算来选择一个计划,通常这主要取决于由SQL Server维护的统计信息。

关于数据库中的列和索引收集的统计信息描述了数据的分布、唯一性以及选择度。构成统计信息以“柱状图”形式展现。

      对于相关列或索引的统计信息,查询优化器会使用它们来计算。默认统计信息由系统自动创建和更新。表变量并不持有统计信息,无论表变量实际大小有多大,查询优化器假定只有一行,而临时表则持有统计信息,并储存供查询优化器使用的信息。

     查询优化器借助于这些统计信息和查询优化树一并计算出最佳的计划,这通常需要一系列的计划,测试不同类型的连接,重组连接顺序,尝试不同的索引等等,直至找到执行最快的计划。这些信息也就是估计开销。每一阶段的开销累积也就是执行计划自身的开销。

      重要的是:估计开销仅仅是一个估计,查询优化器利用充足的时间和最新的统计信息来找到符合查询的执行计划。不过,它还是以尽可能花较少时间来计算出一个最佳计划,这要取决于统计信息。

      在查询优化器生成一个执行计划后,实际的计划则存储在称之为“过程缓存”的内存区域。查询优化器会产生其他的计划并与缓存中先前的计划比较,若找到匹配,则重用该计划。

1.1.3查询执行

一旦生成执行计划,接着就进入了存储引擎(查询计划实际执行的地方),这里不具体讨论存储引擎的细节,生成的执行计划可能会在实际的执行中改变,通常需要满足以下条件:

l 对于并行执行来说,该计划超过了其阀值(执行计划可以使用多处理器来工作,有关详细内容稍后进行介绍)

l 生成计划的统计过期或原来的执行计划发生变化

估计执行计划和实际执行计划

如前所述,有两种类型的执行计划,第一种是由查询优化器输出的计划,称之为“估计执行计划”,第二种是实际执行计划,它是一条查询执行时真正处理的计划。
执行计划重用

SQL Server来说,产生执行计划的开销比较高,因此尽可能的可以重用执行计划。当创建时,会存储在内存中的一块计划缓存区域(通常叫做过程缓存区)。当提交一条SQL到服务器时,查询优化器为其创建一条估计的执行计划,在进入存储引擎前,查询优化器将估计的执行计划与现有“计划缓存区(Plan Cache)”的实际执行计划相比较,如果两者匹配,查询优化器则重用现有的计划,对于复杂查询来说,计划重用避免了创建实际执行计划的开销,即便对于每分钟执行上千次的简单查询来说亦如此。

执行计划并不是永久存储在内存中,SQL SERVER使用一种过期的算法来估计执行计划使用的次数(例如一条开销为10的执行计划,使用了5次,则其过期值为50)。Lazywriter进程,用于释放过程缓存中引用过期的执行计划,通过每次减1的方式来定期地扫描缓存的对象。

当满足以下条件时,该计划从内存中删除:

l 系统需要更多的内存

l 计划的Age值达到了0

l 计划当前并未被使用

一些事件和行为也容易导致执行计划重编译,重编译是代价比较高的操作,尽量避免重编译。以下事件容易导致重编译:

  1. 引用查询的表架构改变
  2. 使用查询的索引改变
  3. 删除查询使用中的索引
  4. 更新引用查询的统计信息
  5. 调用函数,sp_recompile
  6. 使用触发器的表
  7. 在单一查询中,DDL和DML混合使用
  8. 改变执行计划的SET选项
  9. 改变查询中使用的临时表结构或架构

10. 查询中使用的动态视图发生改变

11. 查询中使用的游标选项发生改变

12. 远程行集发生改变(分布式分区视图)

13. 使用客户端游标时,对于FOR BROWSE选项发生改变

由于缓存在执行计划中起着主要作用,需要借助一些工具来查看或分析计划缓存,你可能想查看某个计划编译花费了多长时间或者查看创建不同计划可能会有多大的调整。要清除整个缓存,运行以下命令:

DBCC FREEPROCCACHE

若要查看缓存内的对象来分析优化器和存储引擎如何创建计划,可以借助于动态管理视图或动态管理函数,如下的语句:

   1: SELECT [cp].[refcounts] 
   2: ,[cp].[usecounts] 
   3: ,[cp].[objtype] 
   4: ,[st].[dbid] 
   5: ,[st].[objectid] 
   6: ,[st].[text] 
   7: ,[qp].[query_plan] 
   8: FROM sys.dm_exec_cached_plans cp 
   9: CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st 
  10: CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp ;


通过上面的语句片断我们可以查看该SQL执行时产生的XML计划,也可以直接以图形执行计划打开。

1.1.4实际执行计划与估计执行计划区别

通常你可能区分不出实际执行计划和估计执行计划之间的差异,不过,在某种情况下可能会导致两者间的不同:

l 当统计信息过期

实际执行计划与估计执行计划之间不同的主要原因是由于统计信息与实际数据的不同。这通常是由于时间的增加,数据的添加和删除所致,这也必然导致定义索引的键发生改变或数据分布发生了改变。若自动更新统计开关打开的话,系统仅取样一部分数据,其目的主要降低运行查询的开销。这也说明了随着时间的积累,该统计信息也变得不太精确,这不仅导致了计划的不同,也由于统计数据的过期导致获得性能较劣的执行计划。

l 当估计计划无效时

在一些情况下,估计执行计划并不工作,例如如下的代码片断:

   1: CREATE TABLE TempTable 
   2:     ( 
   3:      Id INT IDENTITY(1, 1) 
   4:     ,Dsc NVARCHAR(50) 
   5:     ); 
   6:  
   7: INSERT INTO TempTable ( Dsc ) 
   8:         SELECT  [Name] 
   9:         FROM    [Sales].[Store]; 
  10:  
  11: SELECT  * 
  12: FROM    TempTable; 
  13:  
  14: DROP TABLE TempTable; 

你可能得到如下错误信息:

Msg 208, Level 16, State 1, Line 7
Invalid Object name 'TempTable'

查询优化器主要生成估计执行计划,并不执行T-SQL。由于查询还未执行,并不存在临时表对象,也就是错误生产的原因所在。若运行该段代码,实际的执行计划则运行正常。

l 当出现并行请求时

当计划满足并行度的阀值,则会生成两个计划。或许在估计执行计划中可能会看到一个计划或并行运算符。而查询实际执行时,可能会看到完全不同的计划,这主要取决于查询引擎运行时是否能支持并行查询还是调用了并行查询。

1.1.5执行计划格式

SQL Server仅提供一种类型的执行计划(估计或实际),但是查看执行计划有三种不同的格式:

u 图形计划

u 文本计划

u XML计划

下面将逐一介绍。

图形计划:

它是最快且最易读,但是隐藏了部分计划数据。估计执行计划和实际执行计划均可以通过图形执行查看。

文本计划:

它略微有点难读,但是提供了更多的有用信息,它也有三种格式:

1. SHOWPLAN_ALL显示估计计划的全部信息

2. SHOWPLAN_TEXT提供有限的数据,不过也显示估计执行计划的信息

3. STATISTICS PROFILE与SHOWPLAN_ALL类似,还提供实际执行计划的数据

XML计划:

XML计划描述了计划中最完整的数据,以结构化的XML格式显示,它也有两种XML计划:

1. SHOWPLAN_XML执行之前由查询优化器产生的计划

2. STATISTICS_XML实际执行计划的XML格式

小结:

上述简要介绍了关于查询执行、执行计划重用以及估计计划与实际计划的不同等,后续将通过例子来介绍。

posted @ 2011-12-02 17:39  Yuejun Sun  阅读(863)  评论(0编辑  收藏  举报