《Microsoft Sql server 2008 Internals》读书笔记--第八章The Query Optimizer(9)
《Microsoft Sql server 2008 Internals》读书笔记--目录索引
本文继续关注分区表(Partitioned Tables) 和数据仓库(Data Warehousing)
SQL Server 2005针对分区表的并行查询的执行有一个局限性。APPLY操作符的使用在对扫描每个交互的分区时有限制,即允许SQL Server 2005对每个表只允许一个线程。虽然也允许并行查询。但大多数情况下还是被忽略了。而且,APPLY模式不考虑分区的大小差异,仍然使用一个线程处理一个最大或最小的分区。
查询优化器在分区琢计划生成时改善了端对端体验。代表分区表的能力使访问分区表和非分区表的差异已经最小化。特别,可参考的并行计划集更加连贯。查询执行组件会动态调整每分区使用一个或多个线程,以便更高效地执行查询。
在SQL Server 2008中,连接协作仍使用apply/nested loops join表示,但其他的案例使用传统表示。
尽管SQL Server 2005在查询计划中暴露了分区ID,但SQL Server 2008在视图中极大隐藏了它。
■数据仓库(Data WareHouseing)
SQL Server包括一些特定的优化以加速数据仓库的查询。数据仓库,其实就是一个大的事实数据和一些小的维度数据表和一些事实表引用的明细信息。即所谓的星型架构和雪花型架构。
数据仓库通常尽力使事实表的每行尽可能小。大的数据,比如字符串,被移走到维度表以消减行内空间。当针对数据仓库作优化时,重要的是不到必要时不扫描事实表。SQL Server能辨识星型和雪花型架构。应用特殊的优化以改善查询性能。首先,SQL Server在数据仓库中排序不同的连接尽量使得扫描事实表前先执行一系列针对维度表的限定操作。 SQL Server 2008也包含针对(帮助减少并行查询时跨线程的数据移动的)位图操作的改进。位图可能会被消减会一个位(bit)。
■Updates
Updates在查询处理中是一个有趣的区域。不仅优化了传统的select查询,而且Updates优化也考虑物理优化比如在每行中多少索引需要被touch,进程是在一段时间内更新还是立即更新,尽可能快的处理变化而避免不必要的死锁等等。
在这部分,我们将要讨论有关的优化。Update处理实际上包含了改变数据的*命令(top-level),Insert,Update,Delete,还有SQL Server 2008新增的Merge。SQL Server几乎一视同仁地对待这些命令。SQL Server中每个Update查询由如下的基本操作组成:
1、决定什么行将被改变(Inserted,updated,deleted,merged)
2、计算任何改变列的新值
3、应用变化到表和任何非聚集索引的结构。
下面的例子显示了Insert操作的查询计划:
注意:Insert查询有一个运算符叫常量扫描(Constant Scan),一个常量扫描在关系代数学中是一个特殊的运算符,它不从表中读取数据而生成行。如果正在往表中插入新行,实际上表中并不存在该行。因此,这个运算符(Constant Scan)创建一个Insert操作来处理(在这个处理过程中,实际上新行并没有被插入)。计算标量操作计算这些值到Inserted中。在上例中,这是一个常量,但实际中可能是任何随意的标量表达式或标量子查询。最后,Insert操作物理地更新主键--聚集索引。
下面的例子显示了Update操作的查询计划:
Update查询从聚集索引中读取值,执行一个Top操作,更新相同的聚集索引。这个Top操作实际上是一个处理ROWCOUNT的容器。除非在会话中执行一个set Rowcount N操作,这个Top必须执行。同时注意本例中,更新命令并没有修改键值到聚集索引。因此,索引中的行并不需要在索引中移动。最后,似乎并没有一个操作符计算新值5到col2。这是错误的!事实上,它被处理了,只是有一个物理优化分解这个命令到Update中去处理了。如果你检查update属性,实际上,查询被直接自动参数化并且目标值被直接提供给了Update操作。
下面的例子显示了Delete操作的查询计划:
我们看到,Delete查询和Update查询非常类似,真实区别是:行最终被删除了。最原始的区别是一个where子句被作为一个条件应用到原始表的Seek操作。
需要注意的是:SQL Server对于物理表和索引生成不同的查询计划。我们看一个简单的例子:
而当一个表是Heap(即没有聚集索引的表时),一个特殊的优化会把操作分解为更小的形式。这称为简单更新(Simple Update,这里的Update包括insert,update,delete,merge计划),它明显加快了速度。但注意仅对Heap有效。
我们看一个Heap例子:
请注意这个查询更新了所有的索引。因为一个新行被创建了。然而,在上图中为什么只有一个操作呢?原来,实际的更新操作都在一个操作中了,如下图:
另外一个用于改善通用update场景的物理优化是:all-in-one或per-row操作。
我们试着更新,但不更新所有的索引。
结果,查询变复杂了,查询在表扫描操作中扫描Heap,执行RowCOUNT top,两个计算标量,一个表更新。此时,查看Update的属性,可以看到只更新i2,i3索引。两个计算标量一个是计算新的值,另一个也是一个物理优化以帮助确认每行是否需要更新,每个索引是否需要更新。SQL Server内置一套机制,包含了处理非更新的Update。即如果表或索引没有变化,则某些列无需更新。
后面几篇将继续关注SQL Server的update计划机制。