您的位置:首页 > 数据库

【SqlServer2005+ 查询优化】深入理解SQL Server查询优化器–构造执行计划

2013-04-11 10:27 573 查看
深入理解SQL Server查询优化器–构造执行计划(PART I)

深入理解SQL Server查询优化器–构造执行计划(PART II)

深入理解SQL Server查询优化器–构造执行计划(PART III)

公开的影响规则的选项

其实我们经常会发现很多T-SQL的开发人员不小心就把优化器的一些优化规则给禁用了。

下表的Join hint { LOOP | HASH | MERGE | REMOTE } 和 查询 hint 就是经常被禁用的。



例如,一个逻辑的GROUP BY操作(包括了DISTINCT)对应的物理操作可能是一个hash 聚合 或者一个 流聚合。这两个规则分别叫做GbAggToHS (Group By Aggregate to Hash) 和GbAggToStrm (Group By Aggregate to Stream)。正常情况下,这两个规则选项对优化器来说都是可以用的,优化器在优化一个逻辑操作树时,通常会在其中选择一个。

当查询hint OPTION(HASH GROUP)出现在一个查询语句的时候,GbAggToStrm 实现规则就被禁用了。这意味着,所有的GROUP BY操作都被实现为GbAggToHS,也就是HASH聚合。

同样,join hint “INNER MERGE JOIN“ 在禁止了nested loop和hash join的规则后才可以被使用。有意思的是,在使用了join hint后,整个查询看起来好像也会呗指定了OPTION(FORCE ORDER)这个hint。

如果我们想要优化器仅仅考虑使用merge和hash join来作为一个查询的策略。我们可以使用查询hint OPTION(MERGE JOIN,HASH JOIN)。这是通过禁止了JNtoNL规则(JOIN to Nested Loops)来实现的,这样优化器就只有sort-merge和hash 连接可以选择(JNtoSM 和 JNtoHS)。使用了连接hint的同时也执行了OPTION (FORCE ORDER).

未公开的特性

警告:以下提供的信息只是用于学习目的,切勿用于生产环境,否则会产生不可预料的后果。

使用Join hint和查询hint并不能让优化器选择所有可要的规则,但我们却可以通过一些未公开的DBCC命令和未公开的DMV( sys.dm_exec_query_transformation_stats)来改变优化器选择规则的方式。

以下的内容在SQL Server 2008和2005上已经验证通过,对应的版本是x86 Developer Editions 10.0.2775 (2008 SP1 CU8) 是9.0.4294 (2005 SP3 CU9)。在其他版本可能并不一定有用。

Trace Flags 和 DBCC 命令

和其他未公开的DBCC选项一样,我们为当前会话需要使能trace flag 3604,这样输出就能显示在像SMSS这样的客户端上了。

SQL code

?
我们可以通过DBCC RULEOFF来关闭一个或者多个优化器规则。这个命令接受一个或者多个规则名字作为参数。例如,为了关闭让逻辑操作变为sort-merge和hash 连接的规则,我们可以执行:

SQL code

?
要开启某个规则,我们可以使用DBCC RULEON,也是同样的语法:

SQL code

?
RULEON和RULEOFF都会返回确认的消息(在开启了trace flag 3604)。但只会影响优化器对当前会话的工作。但受我们开启和关闭DBCC开关的影响,所产生的执行计划可能不是最优的,但也会像正常的执行计划被缓存起来。切记,这些开关最好在个人的测试环境上运行。

要返回到正常的操作,打开被关闭的规则,或者简单的断开并重连服务器。也可以通过运行DBCC FREEPROCCACHE命令来移除将任何次优的执行计划从缓存中移除。

想要看当前哪些规则被打开和关闭,使用DBCC SHOWONRULES和DBCC SHOWOFFRULES命令。这两个命令都不需要参数。

SQL Server 2005 的BUG。

在SQL Server 2005上,SHOWOFFRULES会打印一些列被打开的规则,而SHOWONRULES却打印那些被关闭的规则,二者正好相反。

DBCC SHOWONRULES也不会立即返回任何结果,除非你接着运行DBCC SHOWOFFRULES。被关闭的规则会在SHOWOFFRULES(显示的是打开的规则)之前。

被关闭的规则列表在2005上同样没有被正确的格式化:所有的规则名字都连接在一起了。

在2008上面,这些就没有什么问题。

综合展示

目前,我们已经有了用来产生前面文章中贴出来的部分优化的执行计划的工具。我们可以使用sys.dm_exec_query_transformation_stats DVM来标识出被优化器调用的规则,然后使用新的DBCC 命令来有选择性的关闭一些规则,查看对最后执行计划的影响。

下面是我们一直在AdventureWorks数据库上展示的例子的逻辑关系操作树:



和最开始展示的执行计划:



该执行计划有一个预估的成本值为3.59557,而最终优化后的执行计划的预估执行成本为0.0248906:



生成部分优化的执行计划

使用第3篇文章里展示的DMV和查询,我们可以发现优化器使用了超过20种不同的规则来寻找一个充分优化的执行计划。为了生成非常基础的执行计划,我们可以只开启四个所需的核心规则(2005上需要5个)。

SQL code

?
我们需要关闭其他正常情况下会被考虑使用的规则:

SQL code

?
现在我们可以得到非常基础的执行计划了:

SQL code

?
因为我们关闭了很多重要的规则,因此我们将无法运行在第3篇文章中展示的DMV批处理代码。优化器也无法生成任何正确的执行计划,因为被我们禁用掉了很多规则,所以会返回如下错误:

SQL code

?
如果你想要查看DMV的统计,你需要先清除执行计划缓存(使用DBCC FREEPROCCACHE),然后运行如下修改后的代码:

SQL code

?
可以看到类似如下的结果:

对这些结果的输出,可以看第3篇文章的描述。

Spool规则

接下来,让我们开启BuildSpool的规则来产生更多可选择的执行计划。这是哪些可以引入Table Spool操作符的其中一条规则,使用Table Spool可以提供效率:

SQL code

?
大家自己的查询看到的执行计划可能如下:

当然,这仍然是一个不好的计划,但在嵌套循环的里面引入了Lazy Spool后,已经减少了执行计划的预估成本值,从3.59557到3.12199,是一个可观的改善。

清理工作

不要忘了恢复环境,把被关闭的规则给打开。

SQL code

?
你可以通过运行DBCC SHOWOFFRULES来检查是否所有的规则都被打开了(2005刚好相反)。

最后

你可能会在想,了解这些是否在实际工作中会有帮助。答案是肯定的,只有我们了解了一个东西的内部运行和原理,我们才能更好的使用它。

除非注明,本站文章均为原创或编译,转载请注明: 文章来自sqlpub.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: