《Microsoft Sql server 2008 Internals》读书笔记--第八章The Query Optimizer(3)
《Microsoft Sql server 2008 Internals》读书笔记--目录索引
上文主要介绍了查询可选计划的存储和操作符如(计算标量、计算序列 等)。现在我们继续来了解优化架构。
查询优化器包含了许多执行特定功能的优化的相(phase)。不同的Phase帮助查询优化器在优化进程的最早阶段“最高值”的操作。
一个查询优化里的主要phase如下:
■优化之前
在实际的优化进程之前SQL Server查询处理器有几个步骤要做。这些有助于将树转换为一种更易识别的格式。视图扩展(view expansion)是一种主要的预优化活动。当一个引用视图的查询被编译时,视图的文本被从服务器的元数据中读取并解析。这种设计选择的后果就是多次引用视图的查询在查询被优化前多次被视图扩展。coalescing adjacent UNION 操作是另外一个简化树的预优化转换。这转换语法二叉树(syntactic two-child)格式(如UNION [ALL],INTERSECT [ALL]和EXCEPT [ALL])为一个单个的(拥有更多个子节点的)操作符。这个改写简化了树结构并使查询优化器通过写规则(rule)以影响UNIONs更容易些。例如分组UNION操作使移走重复行更容易,更有效。
■简化(Simplification)
在优化早期,树(在Simpliication Phase内)被标准化并转化为从一种紧密链接的格式为用户语法的(有助于后续处理的)树格式。查询优化器侦探查询中的语义矛盾,移去这些错误,并通过改写查询为一个简单的格式。此外,这个环节执行的改写使得随后的操作(如索引匹配、计算列匹配、语句生成)更易于正确地执行。
the Simplification phase执行大量的树改写。这些活动包括:
1、grouping join together and picking an initial join order,based on cardinality data for each table
2、Finding Contradiction in queries that can allow portions og a query not to be executed
3、performing the necessary work to rearite SELECT liststo match computed columns
■Trival Plan/Auto-Parameterization
在SQL Server中主要的优化路径是一个强大的、基于查询时间成本的模型。当数据库和数据库里的查询变得越来越庞大、越来越复杂,这个模型允许SQL Server解决越来越大的业务问题。运行这个模型的固定的启动成本对于不需要执行复杂操作的应用程序可能是昂贵的。制作一个(用以分隔最小、最大的查询的)单一的路径有时是有挑战性的,当请求和定义差异巨大时。
为了能同时适应小的查询应用,一个快速的路径被加到SQL Server以确认哪些不需要进行成本优化。在不需要优化时,查询优化器会直接生成最佳计划并返回需要执行的系统。例如:
SQL Server查询处理器实际上比这个概念做得更多, 当简单的查询被编译和优化时,查询处理器试图转换这些查询为一个参数化的查询。如果查询被判定为一个trivial(琐碎)的查询,参数化的查询被转换为一个可执行的计划。接着,具有相同规格的未来查询直接运行已存在的编译查询以避免整个查询器范围内优化。这显著地加快了小查应用程序的运行速度。
请看例子:
■limitation
the trivial plan优化在SQL Server 7.0开始启用。SQL Server 2005增加了一些新内容,叫做强制参数化"forced parameterization)",更加积极地实施“自动参数化”。这项新内容不计成本地参数化常量。这样做的一个好处是它可以减少编译、编译时间、在过程缓存中的计划数量,从而改善系统性能。另一方面,这会弱化在不同参数值引起不同计划被选择的机制。these valuesare used in the Query Optimizer's carcinality and property framework to make decisionsabout how many rows will be returned from each possible plan choice,and forced parameterizatiob blocks these optimizations.(这句邀月不知如何翻译为妥?)
■The Memo-Explorimg multiple plans efficiently
查询优化器的核心架构是Memo,这个架构帮助存储运行在查询优化器中的所有规则(Rule)的结果,也帮助指导搜索可能的计划以快速找到一个好的计划从而避免多次搜索一个子树。这种架构加速编译进程,减少内存消耗。它允许查询优化器运行吏高级的优化,特别在比较不同机制的优化器时更加有效。
Memo存储了来自查询树的操作符,并且使用逻辑指针来设置树的边界。如果我们考虑查询
Select * from (select * from A inner join B on A.a=B.b) as D INNER JOIN C ON D.c=C.c
这个过程如下图所示:
在Memo中存储如下:
memo由一系列的group组成。当memo第一次被填充时,每一个操作符被置于各自的组中,操作符之间的引用变为对Memo中组的引用,在这种模型下,存储多个(在Memo的相同组中返回相同结果的)可选计划成为可能。由于这个变化,仅仅通过在Memo的高级组中独立查找最佳的子树成为可能。逻辑属性也被存储在每一个Memo组中,每个组的每个接口(entry)都(为其他初始化可选计划的组)共享该组的属性结构。
例如上图中[(A JOIN B) JOIN C] 与[ A JOIN (B JOIN C)]是等价的,那么Memo中存储的结构更新为:
注意:新的可选计划变成了一个结构,B JOIN C是新增的,因此,一个新的Group被创建,引用 B JOIN C转为引用Group 5,这种设置为在筛选多种可能计划时节省了大量的内存。这种机制的规则是允许Memo在优化进程中浏览新可选计划。
一个优化搜索关口被分成两部分:第一部分,勘探匹配逻辑树规则并生成新的等量替代逻辑树,被插入到Memo中。接下来实现规则运行,从逻辑树生成物理树。一旦物理树被生成,它被成本组件评估决定查询树的成本。结果被存储在针对于该可选分支的Memo中。当所有的物理可选分支和它们的成本被(为Memo中的所有组)生成时,查询优化器找出一个最低成本的查询树,并copy进一个stand-alone tree,这个选择的物理树基本上跟查询界面中展示的评估计划非常像了。
优化进程通过使用多个搜索关口被进一步优化,基于成本分离这些规则,决定如何使用它们更有效。有三个Phase,每一个Phase运行一套勘探和实现规则。这个Phase被配置为使用作为快速对小查询进行优化,而对一好处费成本高昂的查询考虑进一步的改写规则(花更多时间去编译)。例如,索引匹配在第一个Phase中先被执行,而生成的索引视图的匹配直到下一步才会被执行。如果查询优化器在pahse结束处打到了一个足够好的查询计划,则会终止优化。这是通过与先前存储在查询计划中的最佳计划相比得出的。而如果查询计划仍然昂贵,则继续进行另一个Phase以继续查找更优的计划。这种机制允许查询优化器在一个相当宽泛的工作负载下有效工作。
■转换为可执行计划
在搜索的结尾,查询优化器选择一个单个的计划,返回给系统。这个计划被从Memo中复制进一个分离树格式,以便存储在过程缓存中。在这个过程中,一些小的物理改写被执行。最终,这个计划被复制到一小块连续的内存中并被存储在过程缓存中。
本文主要介绍了优化架构,下面两至三篇将继续关注统计(Statistics)、标量评估(Cardinality estimation)和成本(costing)。
这一章感觉非常吃力,主要是这一章的作者使用的语法真的有点像我们的文言文,不是一般的拗口,加上介绍的都是底层的存储引擎架构,不易理解,而且SQL语句的例子也要自己编写并执行。真是快要不想写下去了。