第二章介绍的分析图形执行计划的方法也适用于对文本和XML执行计划的分析,不同的是文本和XML执行计划没有图标来表示,但仍包括相同的运算符。
在先前的版本中,仅提供了基于文本的执行计划,许多人发现不易阅读,尤其对于复杂的计划来说;最终微软添加了“图形执行计划”,图形执行计划相对于文本执行计划来说更易于阅读和分析。要取代文本执行计划,微软在SQL Server 2005中引入了XML执行计划。
与文本执行计划一样,若仅查看原始的XML代码的话,XML执行计划也不易阅读和分析,那你可能会问?既然它们都不易于阅读,微软为何要用XML执行计划取代文本执行计划呢?出于变更有许多原因;从格式上来说,XML是通用的文件格式,可用于编程,另外,XML计划也提供了比先前两种计划更为丰富的执行计划细节信息,此外,XML以可移动格式存储,使得易于共享;例如,你可以发送XML计划给其他DBA,那可以借助于管理控制台进行显示并分析,换句话说,基于文本的执行计划并不提供这些特点。
文本执行计划
既然该特性被取代,那为什么还要学习文本执行计划?大多数时间你还是使用SQL Server 2005作为工作环境,建议把精力放在学习图形执行计划上,了解XML执行计划的使用,若还在管理较早版本如SQL Server 2000,那可能需要学习一下如何阅读文本执行计划,因为通常这些在关于SQL Server的书籍和文章都有所提及,了解如何分析也是有用的。
查询的文本计划
首先看一个先前章节提到的查询,作为提醒,我们截取了图形执行计划:
接下来,我们来获取其文本计划,记住:收集估计的执行计划需要打开SHOWPLAN_ALL开关,开关打开后,后续提交的T-SQL代码并不会执行,除非关闭SHOWPLAN_ALL开关。
1: SET SHOWPLAN_ALL ON
2: GO
3: SELECT ContactID ,
4: LastName ,
5: Phone
6: FROM Person. Contact
7: WHERE EmailAddress LIKE 'sab%'
8: GO
9: SET SHOWPLAN_ALL OFF
10: GO
11:
其执行计划以工作簿的形式显示,如下:
第1行是父结点,StmtText列描述了执行的T-SQL语句,滚动结果到右边,会找到一列叫Type,它描述了节点类型:
对于父节点来说,这一行包含了执行的SQL语句的类型,本例为SELECT,对于其他行来说,其类型为PLAN_ROW,在PLAN_ROW节点中的StmtText列描述了执行的运算类型。
另外StmtText列也包括了三种运算:嵌套循环内连接、索引查找、聚集索引查找。与图形执行计划不同,这里无法采用“自右向左、自上向下”的方法来分析文本执行计划,要理解运算的操作流,我们可以借助于连接语句的“|”符合进行分析,也可以参考NodeID和Parent字段(这两个字项也代表当前节点和它的父节点);对于具有相同Parent号的每一行来说,运算则从上到下的顺序执行,在本例,索引查找首先执行,接着是聚集索引查找。
接下来,我们来看NodeID为3的第3行(索引查找),通过展开StmtText列(或查看Argument列)可以发现,在Person.Contact表上执行了索引查找操作:
1: OBJECT:([AdventureWorks].[Person].[Contact].[IX_Contact_EmailAddress]), SEEK:([AdventureWorks].[Person].[Contact].[EmailAddress]
2: >= N'sab' AND
3: [AdventureWorks].[Person].[Contact].[EmailAddress]
4: < N'saC'), WHERE:([AdventureWorks].[Person].[Contact].[EmailAddress] like N'sab%') ORDERED FORWARD
在DefinedValues列包含了该运算操作的值,这些值也可能是查询中操作的那些(在SELECT或WHERE子句):
[AdventureWorks].[Person].[Contact].[ContactID]
这些值是查询优化器执行查询时产生的中间结果,可以把DefineValue看成临时生成的对象,最后,从图中的EstimateRows列,索引查找操作估计的行为19.8行。
再来看第4行(NodeID为5),执行的操作为“聚集索引查找”,这可能与在图形执行计划下显示的不一样,实际上,这是一个“Key Lookup”操作,我们可以从StmtText列来找出整个内容:
|--Clustered Index Seek(OBJECT:([AdventureWorks].[Person].[Contact].[PK_Contact_ContactID]), SEEK:([AdventureWorks].[Person].[Contact].[ContactID]=[AdventureWorks].[Person].[Contact].[ContactID]) LOOKUP ORDERED FORWARD)
注意到:从EstimateRows列来看,该运算仅返回了1行,不过查看网格最后一列EstimateExecutions,其值为19.8次(当执行查询时,其运算执行了19.8次)。
再来看NodeID为2的第2行,这里使用了嵌套循环内连接,将前面两个操作的结果进行合并,在本例中,其DefinedValue显示为Null,意思是该操作没有新值产生,OutputList显示出查询所需要的列(ContactID,LastName,Phone),像EstimateRows,EstimateIO,TotalSubTreeCost等等,这些信息在图形执行计划都可以找到,这里不再详细介绍。
XML执行计划
我觉得对大多数DBA来说,通过图形的格式查看执行计划是首选的方法,不过对于先前版本来说,对于图形执行计划,不存在基于文件格式的计划用于交换,在SQL Server 2005中这种限制已经移除,引入了XML计划。XML计划是一种可以存储图形执行计划的通用文件,可以在其他DBA和开发人员之间进行分享和交流。
想象得出极少数人会选用XML格式来分析执行计划,这样说,有两点原因:
其一:在XML计划以图形执行计划的形式显示时,存在未归档的数据;例如,XML计划包括了一些额外数据,如缓存计划大小、内存片断(在查询计划中分分配给运算所需要的内存)、优化时使用到的参数列表、缺失索引信息;通常情况下,极少数DBA会关注这些信息,否则会有其他更简单的方法来获取这些信息,如数据库调优向导(DTA)来找出缺失的索引信息。
其二:XML计划显示了许多详细的信息,为经验丰富的DBA来提供了便利的搜索功能来查找查询中具有潜在问题的细节信息,也可以搜索特定的术语,如“索引扫描(Index Scan)”。
另外,XML计划也可以用于Plan Forcing中,这部分在第7章介绍,即你可以让查询优化器使用指定XML计划来执行查询。
在接下来的介绍中,我们来一起看一下XML计划的结构。
估计XML计划
为简单描述,这里使用先前介绍文本执行计划中的查询,这次我们来执行SHOWPLAN_XML命令来捕获估计XML执行计划。
1: SET SHOWPLAN_XML ON ;
2: GO
3: SELECT c. [LastName],
4: a. [City] ,
5: cu. [AccountNumber],
6: st. [Name] AS TerritoryName
7: FROM [Person]. [Contact] c
8: JOIN [Sales] . [Individual] i ON c. [ContactID] = i . [ContactID]
9: JOIN [Sales] . [CustomerAddress] ca ON i. [CustomerID] = ca . [CustomerID]
10: JOIN Person. Address a ON [ca]. [AddressID] = [a]. [AddressID]
11: JOIN [Sales] . Customer cu ON cu . [CustomerID] = i . [CustomerID]
12: JOIN [Sales] . [SalesTerritory] st ON [cu]. [TerritoryID] = [st]. [TerritoryID]
13: WHERE st. [Name] = 'Northeast' AND a. [StateProvinceID] = 55 ;
14: GO
15: SET SHOWPLAN_XML OFF
;
单击链接进入XML文档,其计划在新的窗口打开:
由于输出结果比较长,这里不能显示全部信息。这里介绍一下QueryPlan属性:
它描述了缓存中计划所占用的内存大小、CPU周期、使用的内存信息。此外,在执行计划中,也会注意到MissingIndexes元素,
它记录了优化器创建的执行计划中没有可用索引的表和列的信息;而missing 索引提供的信息也是有用的,易于使用工具找出缺失索引,如数据库调优向导。
通过RelOP节点,执行计划也输出了执行操作的不同物理运算,对于NodeID=0而言,执行的是“NestedLoop”运算:
此处显示的信息与在图形执行计划中显示的一样,与文本执行计划不同(仅显示估计执行计划),XML计划对rebinds和rewinds数做了估计。
实际XML计划
同样使用先前的查询,这里通过SET STATISTICS XML开关来查看其计划信息。
1: SET STATISTICS XML ON ;
2: GO
3: SELECT c. [LastName],
4: a. [City] ,
5: cu. [AccountNumber],
6: st. [Name] AS TerritoryName
7: FROM [Person]. [Contact] c
8: JOIN [Sales] . [Individual] i ON c. [ContactID] = i . [ContactID]
9: JOIN [Sales] . [CustomerAddress] ca ON i. [CustomerID] = ca . [CustomerID]
10: JOIN Person. Address a ON [ca]. [AddressID] = [a]. [AddressID]
11: JOIN [Sales] . Customer cu ON cu . [CustomerID] = i . [CustomerID]
12: JOIN [Sales] . [SalesTerritory] st ON [cu]. [TerritoryID] = [st]. [TerritoryID]
13: WHERE st. [Name] = 'Northeast' AND a. [StateProvinceID] = 55 ;
14: GO
15: SET STATISTICS XML OFF
在查看实际计划时,注意到QueryPlan有一些额外的信息,如DegreeOfParallelism和MemoryGrant。
<QueryPlan DegreeOfParallelism="0" MemoryGrant="1856" CachedPlanSize="56" CompileTime="465" CompileCPU="101" CompileMemory="488">
估计计划与实际计划的其它不同的是实际计划中增加了一个叫RunTimeInformation的元素,该元素显示了线程、实际行数及执行次数。
<RunTimeInformation>
<RunTimeCountersPerThread Thread="0" ActualRows="4" ActualEndOfScans="1" ActualExecutions="1" />
</RunTimeInformation>
小结
如本章介绍的,分析XML计划不是容易的任务,多数DBA不愿花过多时间去掌握它,除非要了解每一个内部的细节信息或想学习如何通过编程的方式来访问数据。若真如此,在学习XML计划前,需要首先掌握XML技术。
此外,DBA应意识到有这样一种携带的格式(XML计划)的优点。