远程Sybase数据库技术支持,联系手机:13811580958,QQ:289965371!

 

随着Sybase被完全整合到SAP下,Sybase原来的支持网站被SAP Support Portal取代。
只有购买了SAP服务的用户才能使用账号登录SAP Support Portal进行介质下载、补丁升级、报Incident等。
目前,原Sybase所有产品(包括:Adaptive Server Enterprise、Sybase IQ、Replication Server、PowerDesigner等)的官方手册仍然可以从http://infocenter.sybase.com/help/index.jsp进行浏览或下载。暂不清楚该网站http://infocenter.sybase.com/help/index.jsp何时会被完全迁移到SAP Support上!
Sybase官方手册英文版有html和pdf两种格式,而中文版手册只有pdf一种格式。为了国内Sybase用户更方便、快捷地搜索Sybase常见产品的官方手册内容,特将中文版Sybase官方手册转为html格式!
Sybase产品官方手册中文版的html格式所有内容的版权归SAP公司所有!本博客站长是Sybase数据库的铁杆粉丝!

如有Sybase数据库技术问题需要咨询,请联系我!

  QQ :289965371 点击这里给我发消息
  Email:

以下官方手册为ASE 15.7 ESD#2中文版:

  1. 新增功能公告 适用于 Windows、Linux 和 UNIX 的 Open Server 15.7 和 SDK 15.7
  2. 新增功能摘要
  3. 新增功能指南
  4. ASE 15.7 发行公告
  5. 配置指南(windows)
  6. 安装指南(windows)
  7. 参考手册:构件块
  8. 参考手册:命令
  9. 参考手册:过程
  10. 参考手册:表
  11. Transact-SQL® 用户指南
  12. 系统管理指南,卷 1
  13. 系统管理指南,卷 2
  14. 性能和调优系列:基础知识
  15. 性能和调优系列:锁定和并发控制
  16. 性能和调优系列:监控表
  17. 性能和调优系列:物理数据库调优
  18. 性能和调优系列:查询处理和抽象计划
  19. 性能和调优系列:使用 sp_sysmon 监控 Adaptive Server
  20. 性能和调优系列:利用统计分析改进性能
  21. 程序员参考 jConnect for JDBC 7.0.7
  22. Adaptive Server Enterprise 中的 Java
  23. 组件集成服务用户指南
  24. Ribo 用户指南
  25. 内存数据库用户指南
  26. Sybase Control Center for Adaptive Server® Enterprise
  27. 安全性管理指南
  28. 实用程序指南

 


< 上一个 | 内容 | 下一步 >

查询计划形状


每个运算符在树中的位置决定了它的执行顺序。执行沿着树最左边的分 支开始,然后进行到右边。为了说明执行过程,本节分步介绍上一节示 例中的查询计划的执行过程。 2-1 显示该查询计划的图形表示。

2-1:查询计划


EMIT VA=

image

MERGE JOIN (1)

image

Inner join VA=

image

SCAN

salesdetailind

MERGE JOIN (2)

Inner join

image

VA= VA=

image

SCAN

sales VA=


SCAN

stores VA=

SORT

image

VA=


为了生成结果行, EMIT 运算符从其子运算符 MERGE JOIN (1) 中调用行, 该子运算符从其左子运算符 SCAN 调用 salesdetailind 的行。当 EMIT 从其 左子运算符收到行时,MERGE JOIN 运算符 (1) 会从其右子运算符 MERGE JOIN (2) 调用行。 MERGE JOIN 运算符 (2) 从其左子运算符 SCAN 调用 sales 的行。

MERGE JOIN 运算符 (2) 从其左子运算符收到行时,它会从其右子运 算符 SCAN 调用行。 SCAN 运算符是数据阻塞运算符。也就是说,它需要 其所有输入行,然后才能对输入行排序,因此 SORT 运算符始终从其子 运算符 SCAN 调用 stores 的行,直到返回所有行。然后 SORT 运算符会 对这些行进行排序,并将第一行传递给 MERGE JOIN 运算符 (2)

MERGE JOIN 运算符 (2) 始终从其左子运算符或右子运算符调用行,直到 它获得在连接键上相互匹配的两行。然后,匹配行向上传递到 MERGE JOIN 运算符 (1)MERGE JOIN 运算符 (1) 也始终从其子运算符调用行, 直到找到匹配行,然后将匹配行向上传递给 EMIT 运算符以返回到客户 端。实际上,已使用左深后缀递归策略对这些运算符进行了处理。

2-2 显示了同一个示例查询的替代查询计划的图形表示。该查询计划 包含所有这些运算符,但树的形状不同。

2-2:替代查询计划

image

EMIT VA=


MergeJoinOp(1) Inner join

VA=

image

MergeJoinOp(2)

Inner join VA=

image

ScanOp

salesdetailind VA=


image

ScanOp sales VA=


ScanOp stores VA=

image

image

SortOp VA=


2-2 中的查询计划相对应的 showplan 输出为:

QUERY PLAN FOR STATEMENT 1 (at line 1).


6 operator(s) under root


The type of query is SELECT. ROOT:EMIT Operator

|MERGE JOIN Operator (Join Type: Inner Join)

| Using Worktable3 for internal storage.

| Key Count: 1

| Key Ordering: ASC

|

| |MERGE JOIN Operator (Join Type:Inner Join)

| | Using Worktable2 for internal storage.

| | Key Count:1

| | Key Ordering:ASC

| |

| | |SCAN Operator

| | | FROM TABLE

| | | sales

| | | Table Scan.

| | | Forward Scan.

| | | Positioning at start of table.

| | | Using I/O Size 2 Kbytes for data pages.

| | | With LRU Buffer Replacement Strategy for data pages.

| |

| | |SORT Operator

| | | Using Worktable1 for internal storage.

| | |

| | | |SCAN Operator

| | | | FROM TABLE

| | | | stores

| | | | Table Scan.

| | | | Forward Scan.

| | | | Positioning at start of table.

| | | | Using I/O Size 2 Kbytes for data pages.

| | | | With LRU Buffer Replacement Strategy for data pages.

|

| |SCAN Operator

| | FROM TABLE

| | salesdetail

| | Index : salesdetailind

| | Forward Scan.

| | Positioning at index start.


| | Index contains all needed columns. Base table will not be read.

| | Using I/O Size 2 Kbytes for index leaf pages.

| | With LRU Buffer Replacement Strategy for index leaf pages.

showplan 输出表达查询计划形状的方法是,使用缩进和竖线 (“|”)符 号来表示哪些运算符在哪些运算符的下面,以及哪些运算符在树的同一 分支或不同分支上。解释树形状的规则有两个:

第一个规则是,管状 “|”符号构成的竖线从运算符的名称开始, 向下继续,经过同一分支上在其下的所有运算符。

子运算符会缩进到每一嵌套层的左侧。

使用这些规则,可以从前面的 showplan 输出派生出 2-2 中查询计划的 形状,步骤如下:

1 ROOT EMIT 运算符位于查询计划树的顶部。

2 MERGE JOIN 运算符 (1) ROOT 的左子运算符。竖线从 MERGE JOIN 运算符 (1) 开始,向下经过整个输出的长度,因此所有其它运算符 都在 MERGE JOIN 运算符 (1) 之下,并且在同一分支上。

3 MERGE JOIN 运算符 (1) 的左子运算符是 MERGE JOIN 运算符 (2)

4 竖线从 MERGE JOIN 运算符 (2) 开始,向下经过 SCANSORT 和另一 个 SCAN 运算符,然后结束。这些运算符均嵌套为 MERGE JOIN 运算 符 (2) 下的子分支。

5 MERGE JOIN 运算符 (2) 下的第一个 SCAN 是其左子运算符,即 sales

表的 SCAN

6 SORT 运算符是 MERGE JOIN 运算符 (2) 的右子运算符, stores 表的

SCAN SORT 运算符的唯一子运算符。

7 stores 表的 SCAN 输出下面,有几个终止的竖线。这表明树的一个 分支已结束。

8 下一个输出是针对 salesdetail 表的 SCAN。它与 MERGE JOIN 运算符 (2) 的缩进相同,表示它们在同一级别上。事实上,该 SCAN MERGE JOIN 运算符 (1) 的右子运算符。


image

注释 大多数运算符不是一元运算符,就是二元运算符。也就是说,它 们的正下方不是有一个子运算符,就是有两个子运算符。有两个以上子 运算符的运算符称为 “n 元运算符”。没有子运算符的运算符是树中的 叶运算符,称为 “零元运算符”。

image


获取查询计划的图形表示的另一种方法是使用命令 set statistics plancost on。有关详细信息,请参见 《Adaptive Server 参考手册:命令》。此命令 用于比较查询计划的估计开销和实际开销。它将其输出显示为表示查询 计划树的半图形化的树。这是一种诊断查询性能问题的非常有用的工具。


查询计划运算符


20 页的表 1-3 列出了查询计划运算符及每个运算符的说明。本节包 含可提供有关各个运算符的详细信息的其它消息。


EMIT 运算符


EMIT 运算符显示在每个查询计划的顶部。 EMIT 是查询计划树的根,且 始终只有一个子运算符。 EMIT 运算符可路由查询的结果行,方法是将 结果行发送到客户端 (一个应用程序或其它 Adaptive Server 实例),或 者将结果行的值赋给局部变量或 fetch into 变量。


SCAN 运算符


SCAN 运算符将行读入查询计划,并使它们可由查询计划中的其它运算 符进行进一步的处理。 SCAN 运算符是叶运算符;也就是说,它没有任 何子运算符。 SCAN 运算符可以从多个源读取行,因此标识它的 showplan 消息的后面始终是 FROM 消息,以标识正在执行哪种 SCANFROM 消息为:FROM CACHEFROM ORFROM LIST FROM TABLE


FROM 高速缓存消息

该消息显示 CACHE SCAN 运算符正在读取单行的内存中的表。


FROM LIST


OR 列表中的行多达 N 行;每一行对应查询中指定的不同的 OR IN 值。

第一条消息显示 OR 扫描正在从包含 IN 列表或同一列中多个 or 子句的值 的内存中的表读取行。 OR 列表只出现在对 in 列表使用特定 or 策略的查 询计划中。第二条消息显示内存中的表可以具有的最大行数 ( N )。因为 OR 列表在填充内存中的表时消除了重复的值,所以 N 可能小于 SQL 语 句中出现的值的数量。例如,以下查询生成了使用特定 or 策略和 OR 列 表的查询计划:

select s.id from sysobjects s where s.id in (1, 0, 1, 2, 3) go

QUERY PLAN FOR STATEMENT 1 (at line 1). STEP 1

The type of query is SELECT.


4 operator(s) under root ROOT:EMIT Operator (VA = 4)

|NESTED LOOP JOIN Operator (VA = 3) (Join Type: Inner Join)

|

| |SCAN Operator (VA = 2)

| | FROM OR List

| | OR List has up to 5 rows of OR/IN values.

|

| |RESTRICT Operator (VA = 2)(0)(0)(0)(8)(0)

| | |SCAN Operator (VA = 1)

| | | FROM TABLE

| | | sysobjects

| | | s

| | | Using Clustered Index.

| | | Index : csysobjects

| | | Forward Scan.

| | | Positioning by key.

| | | Index contains all needed columns. Base table will not be read.

| | | Keys are:

| | | id ASC

| | | Using I/O Size 2 Kbytes for index leaf pages.

| | | With LRU Buffer Replacement Strategy for index leaf pages.


该示例中的 IN 列表中有 5 个值,但只有 4 个值不相同,所以 OR 列表只 将这 4 个不同的值放入其内存中的表。在查询计划示例中, OR 列表是 NESTED LOOP JOIN 运算符的左子运算符,SCAN 运算符是 NESTED LOOP JOIN 运算符的右子运算符。在执行此计划时,NESTED LOOP JOIN 运算 符调用 or 命令以从其内存中的表返回行,然后 NESTED LOOP JOIN 运算 符调用 SCAN 运算符以查找所有匹配的行 (一次一行,使用聚簇索引查 找)。相对于读取 sysobjects 的所有行,再将各行中 sysobjects.id 的值与 IN 列表中的 5 个值作比较,该查询计划示例高效得多。


FROM TABLE


FROM TABLE 显示 PARTITION SCAN 运算符正在读取数据库表。第二条 消息提供表名;如果有相关名,则在下一行输出。在前面的输出示例中 的 FROM TABLE 消息下,sysobjects 是表名,s 是相关名。前面的示例在 FROM TABLE 消息下面还显示了其它几条消息。这些消息提供了有关 PARTITION SCAN 运算符如何指引 Adaptive Server 的访问层从正被扫描 的表获取行的详细信息。

以下消息指出扫描是表扫描,还是索引扫描:

Table Scan — 通过读取表中的页来获取行。

Using Clustered Index — 使用聚簇索引来获取表的行。

Index : indexname — 使用索引来获取表的行。如果该消息的前面没有 “using clustered index”,则使用非聚簇索引。indexname 是将 使用的索引的名称。

这些消息指出表或索引的扫描方向。扫描方向取决于创建索引时指定的 顺序以及在 order by 子句中为列指定的顺序,或其它可由运算符在查询 计划中进一步利用的有用的顺序 (例如,合并连接策略的排序顺序)。

如果 order by 子句包含对索引键的升序或降序限定符,则可以使用反向 扫描,这与 create index 子句中的情况完全相反。

Forward scan Backward scan

扫描方向消息的后面是定位消息,介绍如何访问表或叶级索引:

Positioning at start of table — 从表的第一行开始向前扫描表。

Positioning at end of table — 从表的最后一行开始向后扫描表。

Positioning by key — 索引用于将扫描定位到第一个限定行。

Positioning at index start/positioning at index end — 这些 消息类似于对应的表扫描消息,只不过这是扫描索引,不是扫描表。


如果查询的性质允许限制扫描,则以下消息介绍:

Scanning only the last page of the table — 在扫描使用索引 并搜索标量集合的最大值时显示此消息。如果索引位于查找其最大 值的列,并且索引值按升序排列,则最大值将在最后一页上。

Scanning only up to the first qualifying row — 在扫描使用 索引并搜索标量集合的最小值时显示此消息。


image

注释 如果索引键按降序排列,则上述针对最小集合和最大集合的消息 将对调。

image


在某些情况下,要扫描的索引包含查询中所需的表的所有列。在这种情 况下,将输出以下消息:

Index contains all needed columns. Base table will not be read.

如果索引包含查询所需的所有列,则即使索引列上没有有用的键,优化 程序也可能选择 Index Scan,而不选择 Table Scan。读取索引所需的 I/O 量可能远远小于读取基表所需的 I/O 量。不需要读取基表页的索引 扫描称为覆盖索引扫描

如果 index scan 使用键来定位扫描,则输出以下消息:

Keys are:

Key <ASC/DESC>

该消息显示用作键的列的名称 (各键在各自的输出行上),并显示该键 的索引顺序:ASC 表示升序, DESC 表示降序。

在描述 scan 运算符使用的访问类型的消息后,将输出有关 I/O 大小和缓 冲区高速缓存策略的消息。


I/O 大小消息


I/O 消息为:

Using I/O size N Kbtyes for data pages. Using I/O size N Kbtyes for index leaf pages.

这些消息报告在查询中使用的 I/O 大小。可能的 I/O 大小是 248

16 千字节。



use pubs2 go

set showplan on go

如果查询中使用的表、索引或数据库使用具有大 I/O 池的数据高速缓存, 则优化程序可以选择大 I/O。它可以选择使用一个 I/O 大小来读取索引叶 页,使用另一个不同的大小来读取数据页。这一选择取决于高速缓存中 缓冲池的可用大小、要读取的页数、对象的高速缓存绑定、表或索引页 的集群比。

这两条消息或其中一条消息会出现在 SCAN 运算符的 showplan 输出中。 对于表扫描,只输出第一条消息;对于覆盖索引扫描,只输出第二条消 息。对于需要访问基表的 Index Scan,输出所有这两条消息。

在每个 I/O 大小消息后,将输出高速缓存策略消息:

With <LRU/MRU> Buffer Replacement Strategy for data pages.

With <LRU/MRU> Buffer Replacement Strategy for index leaf pages.

LRU 替换策略中,最近访问的页定位在高速缓存中,以便尽可能长 时间地保留。在 MRU 替换策略中,最近访问的页定位在高速缓存中, 以便快速替换。

在以下查询中显示了示例 I/O 和高速缓存消息:

select au_fname, au_lname, au_id from authors where au_lname = "Williams"

go


QUERY PLAN FOR STATEMENT 1 (at line 1).


1 operator(s) under root


The type of query is SELECT. ROOT:EMIT Operator (VA = 1)

|SCAN Operator (VA = 0)

| FROM TABLE

| authors

| Index : aunmind

| Forward Scan.

| Positioning by key.

| Keys are:

| au_lname ASC


| Using I/O Size 2 Kbytes for index leaf pages.

| With LRU Buffer Replacement Strategy for index leaf pages.

| Using I/O Size 2 Kbytes for data pages.

| With LRU Buffer Replacement Strategy for data pages.

authors 表的 SCAN 运算符使用索引 aunmind,但还必须读取基表页来从 authors 中获取所有必需列。在该示例中,有两条 I/O 大小消息,每条消 息的后面都跟有相应的缓冲区替换消息。

有两种表 SCAN 运算符,它们有其各自的消息 — RID SCAN LOG SCAN


RID scan


use pubs2 go

set showplan on go


Positioning by Row IDentifier (RID) 扫描只位于使用优化程序可 以选择的第二种 or 策略 (常规 or 策略)的查询计划中。当不同的列上 存在多个 or 子句时,可以使用常规 or 策略。优化程序可为之选择常规 or 策略及其 showplan 输出的查询的示例为:

select id from sysobjects where id = 4 or name = 'foo' QUERY PLAN FOR STATEMENT 1 (at line 1).

6 operator(s) under root The type of query is SELECT. ROOT:EMIT Operator (VA = 6)

|RID JOIN Operator (VA = 5)

| Using Worktable2 for internal storage.

|

| |HASH UNION Operator has 2 children.

| | Using Worktable1 for internal storage.

| |

| | |SCAN Operator (VA = 0)

| | | FROM TABLE

| | | sysobjects

| | | Using Clustered Index.

| | | Index : csysobjects

| | | Forward Scan.

| | | Positioning by key.

| | | Index contains all needed columns. Base table will not be read.


|

|

|

|

|

|

|

|

|

|

|

|

|

|

Keys are: id ASC

Using I/O Size 2 Kbytes for index leaf pages.

With LRU Buffer Replacement Strategy for index leaf pages.

| | |SCAN Operator (VA = 1)

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

FROM TABLE

sysobjects

Index : ncsysobjects Forward Scan.

Positioning by key.

Index contains all needed columns. Base table will not be read. Keys are:

name ASC

Using I/O Size 2 Kbytes for index leaf pages.

With LRU Buffer Replacement Strategy for index leaf pages.

| |RESTRICT Operator (VA = 4)(0)(0)(0)(11)(0)

| |

| | |SCAN Operator(VA = 3)

|

|

|

FROM TABLE

|

|

|

sysobjects

|

|

|

Using Dynamic Index.

|

|

|

Forward Scan.

|

|

|

Positioning by Row IDentifier (RID).

|

|

|

Using I/O Size 2 Kbytes for data pages.

|

|

|

With LRU Buffer Replacement Strategy for data pages.

在该示例中, where 子句包含两个分离,分别位于不同的列 (id name) 上。其中每个列上都有索引 (csysobjects ncsysobjects),因此优化程 序选择符合以下条件的查询计划:使用一个索引扫描来查找其 id 列为 4 的所有行,使用另一个索引扫描来查找其 name 为 “foo”的所有行。

因为单个行可能同时包含 ID 4 和名称 “foo”,所以该行将在结果集中 出现两次。为了消除这些重复的行,索引扫描只返回限定行的行标识符 (RID)。两个 RID 流由 HASH UNION 运算符连接,这也会删除任何重复的 RID

具有唯一 RID 的流被传递到 RID JOIN 运算符。 rid join 运算符创建一个 工作表,并使用包含各个 RID 的单列行填充它。然后 RID JOIN 运算符 将其 RID 工作表传递给 RID SCAN 运算符。 RID SCAN 运算符将该工作 表传递到访问层,在那里,该工作表被视为无键的非聚簇索引,然后获 取并返回与 RID 对应的行。


showplan 输出的最后一个 SCAN RID SCAN。从输出示例中可以看到, RID SCAN 输出包含许多前面已讨论过的消息,但还包含两条只为 RID SCAN 输出的消息:

Using Dynamic Index — 表示 SCAN 使用包含 RID 的工作表,该工 作表是在执行过程中由 RID JOIN 运算符构建的,作为查找匹配行 的索引。

Positioning by Row Identifier (RID) — 表示直接通过 RID 查 找行。


Log Scan


use pubs2 go

set showplan on go


Log Scan 只出现在访问已插入或已删除的表的触发器中。这些表是在 执行触发器时通过扫描事务日志动态建立的。仅在 insertdelete update 查询修改了在其上为特定查询类型定义触发器的表之后,才执行触发器。 以下示例是对 titles 表的 delete 查询,该表上定义了称为 deltitle 的删除触 发器:

delete from titles where title_id = 'xxxx' QUERY PLAN FOR STATEMENT 1 (at line 1).

STEP 1

The type of query is DELETE.


2 operator(s) under root


|ROOT:EMIT Operator (VA = 2)


|DELETE Operator (VA = 1)

| The update mode is direct.

|

| |SCAN Operator (VA = 0)

|

|

FROM TABLE

|

|

titles

|

|

Using Clustered Index.

|

|

Index : titleidind

|

|

Forward Scan.

|

|

Positioning by key.

|

|

Keys are:

|

|

title_id ASC


| | Using I/O Size 2 Kbytes for data pages.

| | With LRU Buffer Replacement Strategy for data pages.

|

| TO TABLE

| titles

| Using I/O Size 2 Kbytes for data pages.

此点以上的 showplan 输出针对实际的 delete 查询。以下的输出针对触发 器 deltitle

QUERY PLAN FOR STATEMENT 1 (at line 5). STEP 1

The type of query is COND.


6 operator(s) under root ROOT:EMIT Operator (VA = 6)

|RESTRICT Operator (VA = 5)(0)(0)(0)(5)(0)

|

| |SCALAR AGGREGATE Operator (VA = 4)

|

|

Evaluate Ungrouped COUNT AGGREGATE.

|

|

|

|

|MERGE JOIN Operator (Join Type: Inner Join) (VA = 3)

|

|

| Using Worktable2 for internal storage.

|

|

| Key Count: 1

|

|

| Key Ordering: ASC

|

|

|

|

|

| |SORT Operator (VA = 1)

|

|

| | Using Worktable1 for internal storage.

|

|

| |

|

|

| | |SCAN Operator (VA = 0)

|

|

| | | FROM TABLE

|

|

| | | titles

|

|

| | | Log Scan.

|

|

| | | Forward Scan.

|

|

| | | Positioning at start of table.

|

|

| | | Using I/O Size 2 Kbytes for data pages.

|

|

| | | With MRU Buffer Replacement Strategy for data

pages.

|

|

|

|

|

| |SCAN Operator (VA = 2)

|

|

| | FROM TABLE

|

|

| | salesdetail

|

|

| | Index : titleidind

|

|

| | Forward Scan.


| | | | Positioning at index start.

| | | | Index contains all needed columns. Base table will not be read.

| | | | Using I/O Size 2 Kbytes for index leaf pages.

| | | | With LRU Buffer Replacement Strategy for index leaf pages.


QUERY PLAN FOR STATEMENT 2 (at line 8).


STEP 1

The type of query is ROLLBACK TRANSACTION. QUERY PLAN FOR STATEMENT 3 (at line 9).

STEP 1

The type of query is PRINT.


QUERY PLAN FOR STATEMENT 4 (at line 0).

STEP 1

The type of query is GOTO.

定义触发器 deltitle 的过程包括 4 SQL 语句。使用 sp_helptext deltitle 可 显示 deltitle 的文本。 deltitle 中的第一条语句已编译进查询计划中,其它 三条语句编译进了遗留查询计划中并由过程执行引擎执行,而不是由查 询执行引擎执行。

titles 表的 SCAN 运算符的 showplan 输出通过输出 Log Scan 指示它正在 扫描日志。


DELETE INSERT UPDATE 运算符

DELETEINSERT UPDATE 运算符通常只有一个子运算符。不过,它 们可以使用多达两个的其它子运算符,来强制实施参照完整性约束,并 在对文本列执行 alter table drop 时释放文本数据。

这些运算符通过插入、删除或更新属于目标表的行来修改数据。

DML 运算符的子运算符可以是 SCAN 运算符、 JOIN 运算符或任何数据 流运算符。

可使用不同的更新模式修改数据,如以下消息所指定的:

The Update Mode is <Update Mode>.

表更新模式可以是 directdeferreddeferred for an index

deferred for a variable column。工作表的更新模式始终是立即。



use pubs2 go

set showplan on go

在以下消息中显示数据修改的目标表:

TO TABLE

< 表名 >

还显示用于数据修改的 I/O 大小:

Using I/O Size <N> Kbytes for data pages.

下一个示例使用 DELETE 运算符:

delete from authors where postalcode = '90210' QUERY PLAN FOR STATEMENT 1 (at line 1).

STEP 1

The type of query is DELETE.


2 operator(s) under root ROOT:EMIT Operator (VA = 2)

|DELETE Operator (VA = 1)

| The update mode is direct.

|

| |SCAN Operator (VA = 0)

| | FROM TABLE

| | authors

| | Table Scan.

| | Forward Scan.

| | Positioning at start of table.

| | Using I/O Size 4 Kbytes for data pages.

| | With LRU Buffer Replacement Strategy for data pages.

|

| TO TABLE

| authors

| Using I/O Size 4 Kbytes for data pages.


TEXT DELETE 运算符

在其中 DELETEINSERT UPDATE 运算符可以拥有多个子运算符的另 一种查询计划是针对 alter table drop textcol 命令的,其中 textcol 是其数据 类型为 textimage unitext 的列的名称。此版本的命令将 TEXT DELETE 运算符用于其查询计划。例如:

use tempdb go

create table t1 (c1 int, c2 text, c3 text) go

set showplan on go

alter table t1 drop c2


QUERY PLAN FOR STATEMENT 1 (at line 1).

Optimized using the Abstract Plan in the PLAN clause.


STEP 1

The type of query is ALTER TABLE.


5 operator(s) under root ROOT:EMIT Operator (VA = 5)

|INSERT Operator (VA = 52)

| The update mode is direct.

|

| |RESTRICT Operator (VA = 1)(0)(0)(3)(0)(0)

| |

| | |SCAN Operator (VA = 0)

| | | FROM TABLE

| | | t1

| | | Table Scan.

| | | Forward Scan.

| | | Positioning at start of table.

| | | Using I/O Size 2 Kbytes for data pages.

| | | With LRU Buffer Replacement Strategy for data pages.

|

| |TEXT DELETE Operator

|

|

The update mode is direct.

|

|

|

|

|SCAN Operator (VA = 3)

|

|

|

FROM TABLE

|

|

|

t1

|

|

|

Table Scan.

|

|

|

Forward Scan.


| | | Positioning at start of table.

| | | Using I/O Size 2 Kbytes for data pages.

| | | With LRU Buffer Replacement Strategy for data pages.

|

| TO TABLE

| #syb altab

| Using I/O Size 2 Kbytes for data pages.

使用 alter table 命令删除了 t1 中两个 text 列中的一个列。showplan 输出类似 于 select into 查询计划,因为 alter table 在内部生成了 select into 查询计划。

INSERT 运算符调用其左子运算符 t1 SCAN 来读取 t1 的行,并构建新行

(但只将 c1 c3 列插入 #syb_altab)。当所有新行都插入 #syb_altab 后, INSERT 运算符会调用其右子运算符 TEXT DELETE 来删除已从 t1 中删除 的 c2 列的文本页链。

后处理将 t1 的原始页替换为 #syb_altab 的原始页,以完成 alter table 命令。

TEXT DELETE 运算符只出现在用于删除表的一部分而非全部文本列的

alter table 命令中,并且它总是作为 INSERT 运算符的右子运算符出现。

TEXT DELETE 运算符显示更新模式消息,与 INSERTUPDATE DELETE

运算符完全相同。


强制实施参照完整性的查询计划

INSERTUPDATE DELETE 运算符用于具有一个或多个参照完整性 约束的表时, showplan 输出还显示 DML 运算符的 DIRECT RI FILTER DEFERRED RI FILTER 子运算符。参照完整性约束的类型决定是显示 所有这两个运算符,还是只显示其中一个运算符。

以下示例表明将 insert 插入 pubs3 数据库的 titles 表中。该表有一个名为 pub_id 的列,该列引用 publishers 表的 pub_id 列。titles.pub_id 的参照完整 性约束要求插入 titles.pub_id 的每个值必须在 publishers.pub_id 中具有相 应的值。

查询及其查询计划为:

use pubs3 go

set showplan on

insert into titles values ("AB1234", "Abcdefg", "test", "9999", 9.95, 1000.00, 10, null, getdate(),1)

QUERY PLAN FOR STATEMENT 1 (at line 1). STEP 1

The type of query is INSERT.


4 operator(s) under root


ROOT:EMIT Operator (VA = 3)


|INSERT Operator (VA = 2)

| The update mode is direct.

|

| |SCAN Operator (VA = 1)

| | FROM CACHE

|

| |DIRECT RI FILTER Operator has 1 children.

| |

| | |SCAN Operator (VA = 0)

| | | FROM TABLE

| | | publishers

| | | Index : publishers_6240022232

| | | Forward Scan.

| | | Positioning by key.

| | | Index contains all needed columns. Base table will not be read.

| | | Keys are:

| | | pub_id ASC

| | | Using I/O Size 2 Kbytes for index leaf pages.

| | | With LRU Buffer Replacement Strategy for index leaf pages.

|

| TO TABLE

| titles

| Using I/O Size 2 Kbytes for data pages.

在该查询计划中, INSERT 运算符的左子运算符是 CACHE SCAN,它返回 要插入 titles 的值所在的行。INSERT 运算符的右子运算符是 DIRECT RI FILTER 运算符。

DIRECT RI FILTER 运算符执行对 publishers 表的扫描,以查找其 pub_id 值与要插入到 titles 中的 pub_id 值相匹配的行。如果找到匹配行,则 DIRECT RI FILTER 运算符允许继续执行 insert,但如果在 publishers 中 没有找到 pub_id 的匹配值,则 DIRECT RI FILTER 运算符会中止该命令。

在该示例中,DIRECT RI FILTER 可以在向 titles 插入行时,检查已插入 的每一行的参照完整性约束并对其强制实施参照完整性约束。



use pubs3 go

set showplan on go

下一个示例显示 DIRECT RI FILTER DEFERRED RI FILTER 运算符一

起以不同的模式运算:

update publishers set pub_id = '0001' QUERY PLAN FOR STATEMENT 1 (at line 1).

STEP 1

The type of query is UPDATE.


13 operator(s) under root ROOT:EMIT Operator (VA = 13)

|UPDATE Operator (VA = 1)

| The update mode is deferred_index.

|

| |SCAN Operator (VA = 0)

| | FROM TABLE

| | publishers

| | Table Scan.

| | Forward Scan.

| | Positioning at start of table.

| | Using I/O Size 2 Kbytes for data pages.

| | With LRU Buffer Replacement Strategy for data pages.

|

| |DIRECT RI FILTER Operator (VA = 7) has 1 children.

| |

| | |INSERT Operator (VA = 6)

| | | The update mode is direct.

| | |

| | | |SQFILTER Operator (VA = 5) has 2 children.

| | | |

| | | | |SCAN Operator (VA = 2)

| | | | | FROM CACHE

| | | |

| | | | Run subquery 1 (at nesting level 0).

| | | |

| | | |QUERY PLAN FOR SUBQUERY 1 (at nesting level 0 and at line 0).

| | | |

| | | | Non-correlated Subquery.

| | | | Subquery under an EXISTS predicate.


|

|

|

|

|

|

|

|

|SCALAR AGGREGATE Operator (VA = 4)

|

|

|

|

|

Evaluate Ungrouped ANY AGGREGATE.

|

|

|

|

|

Scanning only up to the first qualifying row.

|

|

|

|

|

|

|

|

|

|

|SCAN Operator (VA = 3)

| | | | | | FROM TABLE

| | | | | | titles

| | | | | | Table Scan.

| | | | | | Forward Scan.

| | | | | | Positioning at start of table.

| | | | | | Using I/O Size 2 Kbytes for data pages.

| | | | | | With LRU Buffer Replacement strategy for data

pages.

| | | |

| | | | END OF QUERY PLAN FOR SUBQUERY 1.

| | |

| | | TO TABLE

| | | Worktable1.

|

| |DEFERRED RI FILTER Operator has (VA = 12) 1 children.

| |

| | |SQFILTER Operator (VA = 11) has 2 children.

| | |

| | | |SCAN Operator (VA = 8)

|

|

|

| FROM TABLE

|

|

|

| Worktable1.

|

|

|

| Table Scan.

|

|

|

| Forward Scan.

|

|

|

| Positioning at start of table.

|

|

|

| Using I/O Size 2 Kbytes for data pages.

|

|

|

| With LRU Buffer Replacement Strategy for data pages.

|

|

|

|

|

|

Run subquery 1 (at nesting level 0).

|

|

|

|

|

|

QUERY PLAN FOR SUBQUERY 1 (at nesting level 0 and at line 0).

|

|

|

|

|

|

Non-correlated Subquery.

|

|

|

Subquery under an EXISTS predicate.

|

|

|

|

|

|

|SCALAR AGGREGATE Operator (VA = 10)

|

|

|

| Evaluate Ungrouped ANY AGGREGATE.

|

|

|

| Scanning only up to the first qualifying row.

|

|

|

|

|

|

|

| |SCAN Operator (VA = 9)

|

|

|

| | FROM TABLE


|

|

|

|

|

publishers

|

|

|

|

|

Index : publishers_6240022232

|

|

|

|

|

Forward Scan.

|

|

|

|

|

Positioning by

key.

|

|

|

|

|

Index contains

all needed columns. Base table will

not be read.

|

|

|

|

|

Keys are:

|

|

|

|

|

pub_id ASC

|

|

|

|

|

Using I/O Size

2 Kbytes for index leaf pages.

| | | | | With LRU Buffer Replacement Strategy for index leaf

pages.

| | |

| | | END OF QUERY PLAN FOR SUBQUERY 1.|

| TO TABLE

| publishers

| Using I/O Size 2 Kbytes for data pages.

titles 的参照完整性约束要求,对于 titles.pub_id 的每个值,都必须存在 publishers.pub_id 的一个值。不过,该示例查询更改了 publisher.pub_id 的 值,因此必须执行检查以保持参照完整性约束。

该示例查询可以更改 publishers 中若干行的 publishers.pub_id 的值,因此 在处理完 publishers 的所有行之前,无法执行确保 titles.pub_id 的所有值 仍位于 publisher.pub_id 中的检查。

该示例调用延迟参照完整性检查:在读取 publishers 的每一行时, UPDATE 运算符会调用 DIRECT RI FILTER 运算符以在 titles 中搜索 pub_id 的值与 要更改的值相同的行。如果找到一行,则表明 pub_id 的此值必须仍存在 于 publishers 中以保持 titles 的参照完整性约束,因此 pub_id 的值被插入 WorkTable1 中。

在更新了 publishers 的所有行后, UPDATE 运算符会调用 DEFERRED RI FILTER 运算符来执行其子查询,以验证 Worktable1 中的所有值是否仍位 于 publishers 中。DEFERRED RI FILTER 的左子运算符是一个从 Worktable1 读取行的 SCAN。右子运算符是一个执行存在子查询以在 publishers 中查 找匹配值的 SQFILTER 运算符。如果没有找到匹配值,则该命令中止。

本节中的示例只在两个表之间使用简单的参照完整性约束。 Adaptive Server 最多允许每个表有 192 种约束,因此可以生成更复杂的查询计划。 当必须强制实施多个约束时,查询计划中仍只有一个 DIRECT RI FILTER DEFERRED RI FILTER 运算符,但这些运算符可以有多个子计划,每 个必须强制实施的约束一个子计划。


JOIN 运算符


Adaptive Server 提供了四种主要的 JOIN 运算符策略:NESTED LOOP JOINMERGE JOINHASH JOIN NARY NESTED LOOP JOIN,后者是 NESTED LOOP JOIN 的变体。在 15.0 以前的版本中, NESTED LOOP JOIN 是主要 JOIN 策略。此外还提供 MERGE JOIN,但缺省情况下不启 用该策略。

下面将对每个 JOIN 运算符做进一步的介绍,包括各种算法的一般说明。 这些说明大致概括了各种 JOIN 策略所需的处理。


NESTED LOOP JOIN


NESTED LOOP JOIN (最简单的连接策略)是二元运算符,其左子运算 符构成外部数据流,其右子运算符构成内部数据流。

对来自外部数据流的每一行,打开内部数据流。通常右子运算符是 scan 运算符。打开内部数据流能够有效地将扫描定位在限定所有可搜索参数 的第一行。

限定行返回到 NESTED LOOP JOIN 的父运算符。继续调用连接运算符以 从内部流返回限定行。

在为当前外部行返回内部流的最后一个限定行后,内部流关闭。执行调 用以从外部流获取下一个限定行。该行中的值提供了用于打开扫描并将 扫描定位到内部流的可搜索参数。此过程一直继续,直到 NESTED LOOP JOIN 的左子运算符返回 End Of Scan

-- Collect all of the title ids for books written by "Bloom". select ta.title_id

from titleauthor ta, authors a where a.au_id = ta.au_id

and au_lname = "Bloom" go

QUERY PLAN FOR STATEMENT 1 (at line 2). STEP 1

The type of query is SELECT.


3 operator(s) under root ROOT:EMIT Operator (VA = 3)

|NESTED LOOP JOIN Operator (Join Type: Inner Join)

|

| |SCAN Operator (VA = 0)


| | FROM TABLE

| | authors

| | a

| | Index : aunmind

| | Forward Scan.

| | Positioning by key.

| | Keys are:

| | au_lname ASC

| | Using I/O Size 2 Kbytes for index leaf pages.

| | With LRU Buffer Replacement Strategy for index leaf pages.

| | Using I/O Size 2 Kbytes for data pages.

| | With LRU Buffer Replacement Strategy for data pages.

|

| |SCAN Operator (VA = 1)

| | FROM TABLE

| | titleauthor

| | ta

| | Using Clustered Index.

| | Index : taind

| | Forward Scan.

| | Positioning by key.

| | Keys are:

| | au_id ASC

| | Using I/O Size 2 Kbytes for data pages.

| | With LRU Buffer Replacement Strategy for data pages.

authors 表与 titleauthor 表连接。已选择 NESTED LOOP JOIN 策略。NESTED LOOP JOIN 运算符的类型为 “Inner Join”。首先,打开 authors 表,定位 到 l_name 值为 “Bloom”的第一行 (使用 aunmind 索引)。然后,打开 titleauthor 表,使用聚簇索引 “taind”定位到第一行,其 au_id 等于当前 authors 的行的 au_id 值。如果没有对查找内部数据流有用的索引,则优 化程序可能生成重新格式化策略。

通常,如果有可用于限定内部数据流上连接谓词的有用索引,则 NESTED LOOP JOIN 策略有效。


MERGE JOIN


MERGE JOIN 运算符是二元运算符。左子运算符和右子运算符分别是外 部数据流和内部数据流。这两个数据流均必须按 MERGE JOIN 的键值进 行排序。



select ta.title_id

首先,从外部数据流获取行。这样可以初始化 MERGE JOIN 的连接键 值。然后,从内部数据流获取行,直到遇到其键值等于 (如果键列按 降序排序,则为小于)或大于初始化键值的行。如果连接键相符,则传 递该限定行以进行其它处理,然后继续调用 MERGE JOIN 运算符以从当 前活动数据流中获取行。

如果新值大于当前的比较键,则这些值将在从其它数据流获取行时用作 新的比较连接键。此过程一直继续,直到用尽了所有数据流。

通常,如果数据流扫描要求必须处理大多数行,并且任何输入数据流已 按连接键排序 (如果这些数据流很大),则 MERGE JOIN 策略有效。

from titleauthor ta, authors a where a.au_id = ta.au_id

and au_lname = "Bloom" go


QUERY PLAN FOR STATEMENT 1 (at line 2).


STEP 1

The type of query is EXECUTE. Executing a newly cached statement.

QUERY PLAN FOR STATEMENT 1 (at line 1). STEP 1

The type of query is SELECT.


3 operator(s) under root ROOT:EMIT Operator (VA = 3)

|MERGE JOIN Operator (Join Type: Inner Join)

| Using Worktable2 for internal storage.

| Key Count: 1

| Key Ordering: ASC

|

| |SORT Operator

| | Using Worktable1 for internal storage.

| |

| | |SCAN Operator

| | | FROM TABLE

| | | authors

| | | a

| | | Index : aunmind

| | | Forward Scan.


|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

Positioning by key. Keys are:

au_lname ASC

Using I/O Size 2 Kbytes for With LRU Buffer Replacement Using I/O Size 2 Kbytes for With LRU Buffer Replacement


index leaf pages.

Strategy for index leaf pages. data pages.

Strategy for data pages.

| |SCAN Operator

|

|

|

|

|

|

|

|

|

|

|

|

|

|

FROM TABLE

titleauthor ta

Index : auidind Forward Scan.

Positioning at index start. Using I/O Size 2 Kbytes for


index leaf pages.

|

|

|

|

|

|

With LRU Buffer Replacement Using I/O Size 2 Kbytes for With LRU Buffer Replacement

Strategy for index leaf pages. data pages.

Strategy for data pages.

在上述示例中, sort 运算符是左子运算符或外部数据流。 sort 运算符的 数据源是 authors 表。sort 运算符是必需的,因为 authors 表在 au_id 上没 有索引,否则可以提供必需的排序顺序。 titleauthor 表的扫描是右子运 算符 / 内部数据流。该扫描使用可为 MERGE JOIN 策略提供必需顺序的 auidind 索引。

从外部数据流 (authors 表是初始数据源)获取行以建立初始连接键比 较值。然后从 titleauthor 表获取行,直到找到其连接键等于或大于比较 键的行。

具有匹配键的内部数据流行存储在高速缓存中,以便需要重新获取它 们。当外部数据流包含重复键时重新获取这些行。在获取了大于当前连 接键比较值的 titleauthor.au_id 值后,MERGE JOIN 运算符将开始从外部数 据流获取行,直至找到等于或大于当前 titleauthor.au_id 值的连接键值。 此时,需重新开始扫描内部数据流。

MERGE JOIN 运算符的 showplan 输出中包含一条消息,指出将使用哪个 工作表作为内部数据流的后备存储。如果高速缓存的内存中不再能够容 纳具有重复连接键的内部行,则将其写入工作表中。高速缓存的行的宽 度限于 64 千字节。


HASH JOIN


select ta.title_id


HASH JOIN 运算符是二元运算符。其左子运算符生成建立输入数据流。 其右子运算符生成探查输入数据流。在从 HASH JOIN 运算符请求第一行 时,通过完全读取建立输入数据流来生成建立集。从输入数据流读取每 一行并使用散列键将其散列到适当的桶中。

如果没有足够的内存来容纳整个建立集,会将溢出的部分存放到磁盘 上。这一部分称为散列分区,不应与表分区混淆。散列分区由散列桶集 合构成。在读取整个左子运算符的数据流后,读取探查输入。

散列探查集的每一行。在相应的建立桶中进行查找以检查是否存在具有匹 配散列键的行。如果建立集的桶位于内存中,则会发生这种情况。如果探 查行溢出,则会将其写入相应的溢出探查分区。当探查行的键与建立行的 键相匹配时,则会向上传递这两行的列的必要投影以进行其它处理。

HASH JOIN 算法的后续递归传递中处理溢出分区。在每次传递中都使 用新的散列种子,以便在不同的散列桶间重新分配数据。此递归处理将 一直继续,直到最后一个溢出分区完全位于内存之中。当建立集的散列 分区包含许多重复项时, HASH JOIN 运算符会重新执行 NESTED LOOP JOIN 处理。

通常,如果必须处理源集中的大多数行,并且连接键上没有固有的有用 排序,或者没有可升级为调用运算符的有用排序 (如连接键上的 order by 子句),则 HASH JOIN 策略非常适用。如果其中一个数据集非常小, 可以完全位于内存中,则 HASH JOIN 的执行效果尤其好。在这种情况 下,不会发生任何溢出,并且执行该 HASH JOIN 算法不需要任何 I/O

from titleauthor ta, authors a where a.au_id = ta.au_id

and au_lname = "Bloom"


QUERY PLAN FOR STATEMENT 1 (at line 2).


3 operator(s) under root The type of query is SELECT. ROOT:EMIT Operator

|HASH JOIN Operator (Join Type: Inner Join)

| Using Worktable1 for internal storage.

|

| |SCAN Operator

| | FROM TABLE

| | authors


|

|

|

|

|

|

|

|

|

|

|

|

|

|

a

Index : aunmind Forward Scan.

Positioning by key. Keys are:

au_lname ASC

Using I/O Size 2 Kbytes for


index leaf pages.

|

|

|

|

|

|

|

With LRU Buffer Replacement Using I/O Size 2 Kbytes for With LRU Buffer Replacement

Strategy for index leaf pages. data pages.

Strategy for data pages.

| |SCAN Operator

|

|

|

|

|

|

|

|

|

|

|

|

|

|

FROM TABLE

titleauthor ta

Index : auidind Forward Scan.

Positioning at index start. Using I/O Size 2 Kbytes for


index leaf pages.

|

|

|

|

|

|

With LRU Buffer Replacement Using I/O Size 2 Kbytes for With LRU Buffer Replacement

Strategy for index leaf pages. data pages.

Strategy for data pages.

在上述示例中,建立输入数据流的源是 author.aunmind 的索引扫描。

该扫描只返回 au_lname 值为 “Bloom”的行。然后按这些行的 au_id 值 散列这些行,并将其放入相应的散列桶中。在初始建立阶段完成后,打 开并扫描探查流。按 au_id 列散列源索引 titleauthor.auidind 的每一行。产 生的散列值用于确定应在建立集的哪个桶中搜索匹配的散列键。建立集 的散列桶中的每一行与探查行的散列键比较是否相等。如果行匹配,则 titleauthor.au_id 列返回到 EMIT 运算符。

HASH JOIN 运算符的 showplan 输出包含一条消息,指出将使用哪个工作 表作为溢出分区的后备存储。输入行的宽度限于 64 千字节。


NARY NESTED LOOP JOIN 运算符

优化程序从不评估或选择 NARY NESTED LOOP JOIN 策略。它是在代码生 成过程中构造的运算符。如果编译器找到包含两个或更多个左深 NESTED LOOP JOIN 的系列,则尝试将它们转换为 NARY NESTED LOOP JOIN 运 算符。如果满足其它两个要求,还可以转换扫描;每个 NESTED LOOP JOIN 运算符的类型为 “inner join”,每个 NESTED LOOP JOIN 的右子运 算符为 SCAN 运算符。允许 RESTRICT 运算符位于 SCAN 运算符之上。

与执行一系列 NESTED LOOP JOIN 运算符相比,执行 NARY NESTED LOOP JOIN 在性能方面具有优势。以下示例阐明两种执行方法之间的根本区别。


使用一系列 NESTED LOOP JOIN,扫描可以根据前面的扫描初始化的可 搜索参数的值消除行。该扫描可能不是失败的扫描前面紧邻的扫描。使 用一系列 NESTED LOOP JOIN,将完全读取前面的扫描,尽管它对失败 的扫描没有任何影响。这可能导致产生大量不需要的 I/O。而使用 NARY NESTED LOOP JOIN,获取的下一行来自产生失败的可搜索参数值的扫 描,这会大大提高效率。

select a.au_id, au_fname, au_lname

from titles t, titleauthor ta, authors a where a.au_id = ta.au_id

and ta.title_id = t.title_id and a.au_id = t.title_id and au_lname = "Bloom"

QUERY PLAN FOR STATEMENT 1 (at line 1).


STEP 1

The type of query is SELECT.


4 operator(s) under root


|ROOT:EMIT Operator (VA = 4)

|

| |N-ARY NESTED LOOP JOIN Operator (VA = 3) has 3 children.

|

|

|

|


|


SCAN Operator (VA = 0)

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

FROM TABLE

authors a

Table Scan. Forward Scan.

Positioning at start of table.

Using I/O Size 2 Kbytes for data pages.

With LRU Buffer Replacement Strategy for data pages.

| | |SCAN Operator (VA = 1)

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|


|

|

FROM TABLE

titleauthor ta

Table Scan. Forward Scan.

Positioning at start of table.

Using I/O Size 2 Kbytes for data pages.

With LRU Buffer Replacement Strategy for data pages.


SCAN Operator (VA = 2) FROM TABLE


|

|

|

titles

|

|

|

t

|

|

|

Index : titles_6720023942

|

|

|

Forward Scan.

|

|

|

Positioning by key.

|

|

|

Index contains all needed columns. Base table will not be read.

|

|

|

Keys are:

|

|

|

title_id ASC

|

|

|

Using I/O Size 2 Kbytes for index leaf pages.

|

|

|

With LRU Buffer Replacement Strategy for index leaf pages.

2-3 描述了一系列 NESTED LOOP JOIN

2-3:包含 Nested loop join Emit 运算符树

Emit

(VA=6)

image

image

NestLoopJoin InnerJoin (VA = 5)


image

image

NestLoopJoin InnerJoin (VA = 3)

IndexScan titleidind (t2) (VA = 4)


IndexScan aunmid (a) (VA = 0)

image

Restrict (0) (0) (4) (0)

(VA = 2)

image

IndexScan auidind (ta) (VA = 1)


所有查询处理器运算符都被赋予了虚拟地址。 2-3 中包含 VA = 的行 报告给定运算符的虚拟地址。


有效的连接顺序为 authorstitleauthortitlesRESTRICT 运算符是 titleauthors 的扫描的父运算符。下面将该计划转换为 NARY NESTED LOOP JOIN 计划:

2-4NARY NESTED LOOP JOIN 运算符


EMIT (VA=6)

image

NaryNLJoin (VA = 4)

image

IndexScan (VA = 0)

aunmid (a)


image


image

RESTRICT (VA = 2)

image

(0) (0) (4) (0)


image

NaryNLJoin (VA = 4)


image

NaryNLJoin (VA = 4)


IndexScan (VA = 1)

auidind(ta)

IndexScan (VA = 3)

titleidind(t)


转换保持 authorstitleauthor titles 的原始连接顺序。在上述示例中, titles 的扫描有两个可搜索的参数 — ta.title_id = t.title_id a.au_id = t.title_id。 因此,对 titles 的扫描可能因由 titleauthor 的扫描建立的可搜索参数值而 失败,也可能因由 authors 的扫描建立的可搜索参数值而失败。如果因 authors 的扫描设置的可搜索参数值而没有从 titles 的扫描返回任何行, 则继续扫描 titleauthor 没有任何意义。对于从 titleauthor 获取的每一行, titles 的扫描将失败。只有在从 authors 获取新行时,对 titles 的扫描才可 能成功。这是已实现 NARY NESTED LOOP JOIN 的原因;对于对连续扫 描返回的行没有作用的表,它们不再进行无用的读取。

在该示例中, NARY NESTED LOOP JOIN 运算符关闭 titleauthor 的扫描, 从 authors 获取新行,根据从 authors 中获取的 au_id 重新定位 titleauthor 的扫描。这又是一个显著的性能改进,因为它不再对 titleauthor 表进行 无用的读取,并清除了可能发生的相关 I/O


半连接


select title

from titles


半连接是 NESTED LOOP JOIN 运算符的变体,其结果集中包括 NESTED LOOP JOIN 运算符。当在两个表之间进行半连接时, Adaptive Server 会 从包含第二个表中一个或多个匹配的第一个表返回行 (常规连接从第一 个表只返回一次匹配行)。也就是说,半连接会在找到第一个匹配值时 返回行,然后停止处理,而不是扫描一个表以返回所有匹配值。半连接 也称为 “存在连接”。

例如,如果对 titles titleauthor 表执行半连接:

where title_id in (select title_id from titleauthor) and title like "A Tutorial%"

QUERY PLAN FOR STATEMENT 1 (at line 1).


STEP 1

The type of query is SELECT.


4 operator(s) under root


|ROOT:EMIT Operator (VA = 4)

|

| |NESTED LOOP JOIN Operator (VA = 3) (Join Type: Left Semi Join)

| |

| | |RESTRICT Operator (VA = 1)(0)(0)(0)(6)(0)

| | |

| | | |SCAN Operator (VA = 0)

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

FROM TABLE

titles

Index : titleind Forward Scan.

Positioning by key. Keys are:

title ASC

Using I/O Size 2 Kbytes for


index leaf pages.

|

|

|

|

With LRU Buffer Replacement

Strategy for index leaf pages.

|

|

|

|

Using I/O Size 2 Kbytes for

data pages.

|

|

|

|

|

|

With LRU Buffer Replacement

Strategy for data pages.

| | |SCAN Operator (VA = 2)

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

FROM TABLE

titleauthor

Index : titleidind Forward Scan.

Positioning by key.


|

|

|

Index contains all needed columns. Base table will not be read.

|

|

|

Keys are:

|

|

|

title_id ASC

|

|

|

Using I/O Size 2 Kbytes for index leaf pages.

|

|

|

With LRU Buffer Replacement Strategy for index leaf pages.


Distinct 运算符


有三种可用于执行差别运算的一元运算符:GROUP SORTED DistinctSORT Distinct HASH Distinct。且各有优缺点。优化程序选择在整 个查询计划的上下文中使用相对高效的 distinct 运算符。

有关所有查询处理器运算符的列表和说明,请参见 20 页的表 1-3


GROUP SORTED Distinct 运算符

您可以使用 GROUP SORTED Distinct 运算符来执行差别运算。 GROUP SORTED Distinct 要求输入数据流按不同的列进行排序。它从其子运算 符读取行,并初始化要过滤的当前不同列中的值。

该行返回到父运算符。当再次调用 GROUP SORTED 运算符以获取另一行 时,它从其子运算符获取另一行并将值与当前高速缓存的值作比较。如 果是重复值,则放弃该行,然后再次调用子运算符以获取新行。

这个过程将一直继续,直到找到新的不同行。高速缓存该行的不同列中 的值,以便稍后用于消除相同的行。当前行返回到父运算符以做进一步 处理。

GROUP SORTED Distinct 运算符返回已排序的数据流。优化程序可以 使用它返回已排序的不同数据流这个属性来提高其它上游处理能力。 GROUP SORTED Distinct 运算符是非阻塞运算符。它在获取了不同行 后立即将该行返回给它的父运算符。它不需要处理完整个输入数据流即 可开始返回行。下列查询收集不同的作者的姓和名:

select distinct au_lname, au_fname from authors

where au_lname = "Bloom"

QUERY PLAN FOR STATEMENT 1 (at line 2). STEP 1

The type of query is SELECT.


2 operator(s) under root ROOT:EMIT Operator (VA = 2)


|GROUP SORTED Operator (VA = 1)

|Distinct

|

| |SCAN Operator (VA = 0)

| | FROM TABLE

| | authors

| | Index : aunmind

| | Forward Scan.

| | Positioning by key.

| | Index contains all needed columns. Base table will not be read.

| | Keys are:

| | au_lname ASC

| | Using I/O Size 2 Kbytes for index leaf pages.

| | With LRU Buffer Replacement Strategy for index leaf pages.

该查询计划选择使用 GROUP SORTED Distinct 运算符来应用 distinct 属 性,因为 scan 运算符按不同列 au_lname au_fname 的排序顺序返回行。 GROUP SORTED 不会产生任何 I/O,且 CPU 开销也最低。

您可以使用 GROUP SORTED Distinct 运算符实现矢量集合。请参见 77 页的 “矢量集合运算符 showplan 输出显示行 Distinct 以指 出该 GROUP SORTED Distinct 运算符正在实现 distinct 属性。


SORT Distinct 运算符

SORT Distinct 运算符不要求其输入数据流按不同的键列进行排序。它是 阻塞运算符,可读取其子运算符的所有数据流并在读取行时排序行。对 所有行排序后,将不同的行返回给父运算符。返回按不同的键列排序的 行。如果内存中无法容纳整个输入集,则使用内部工作表作为后备存储。

QUERY PLAN FOR STATEMENT 1 (at line 1)


STEP 1

The type of query is SELECT.


2 operator(s) under root ROOT:EMIT Operator (VA = 2)

|SORT Operator

| Using Worktable1 for internal storage.

|

| |SCAN Operator

|

|

FROM TABLE

|

|

authors

|

|

Table Scan.

|

|

Forward Scan.


| | Positioning at start of table.

| | Using I/O Size 2 Kbytes for data pages.

| | With LRU Buffer Replacement Strategy for data pages.

authors 表的扫描不返回按不同的键列排序的行。这要求使用 SORT Distinct 运算符,而不是 GROUP SORTED Distinct 运算符。 SORT 运 算符的不同键列是 au_lname au_fnameshowplan 输出指明当内存中 无法容纳整个输入集时,将使用 Worktable1 进行磁盘存储。


HASH Distinct 运算符

HASH Distinct 运算符不要求其输入集按不同的键列排序。它是非阻塞 运算符。从子运算符读取行并按不同的键列散列。这决定了行所在的桶 的位置。然后搜索相应的桶以查看是否已存在该键。如果行包含重复的 键,则放弃该行,然后从子运算符获取另一行。如果没有存在任何重复 的不同键,则将该行添加到桶中,并将该行向上传递给父运算符以做进 一步的处理。返回行时没有按不同的键列对其排序。

当输入集尚未按不同的键列排序时,或者当优化程序无法利用来自计划 中稍后的差别处理的排序时,通常使用 HASH Distinct 运算符。

select distinct au_lname, au_fname from authors

where city = "Oakland" go

QUERY PLAN FOR STATEMENT 1 (at line 1). STEP 1

The type of query is SELECT.


2 operator(s) under root ROOT:EMIT Operator (VA = 2)

|HASH DISTINCT Operator (VA = 1)

| Using Worktable1 for internal storage.

|

| | SCAN Operator (VA = 0)

| | FROM TABLE

| | authors

| | Table Scan.

| | Forward Scan.

| | Positioning at start of table.

| | Using I/O Size 2 Kbytes for data pages.

| | With LRU Buffer Replacement Strategy for data pages.


在上述示例中, authors 表扫描的输出没有排序。优化程序可以选择使 用 SORT Distinct HASH Distinct 策略。SORT Distinct 策略提供 的排序在计划中的其它任何部分都不可用,因此优化程序很可能选择使 用 HASH Distinct 策略。优化程序最终将根据开销估计做出决定。HASH Distinct 的开销通常较小,因为未排序的输入数据流可随即消除驻留 分区的行。 SORT Distinct 运算符在对整个数据集排序之前无法消除 任何行。

HASH Distinct 运算符的 showplan 输出报告将使用 Worktable1。如果内 存中无法容纳不同行结果集,则需要工作表。在这种情况下,会将部分 处理的组写入磁盘。


矢量集合运算符


有三种用于矢量集合的一元运算符。它们是 GROUP SORTED COUNT AGGREGATEHASH VECTOR AGGREGATE GROUP INSERTING 运算符。

有关所有查询处理器运算符的列表和说明,请参见 20 页的表 1-3


GROUP SORTED COUNT AGGREGATE 运算符

74 页的 “ GROUP SORTED Distinct 运算符”中所述, GROUP SORTED COUNT AGGREGATE 非阻塞运算符是 GROUP SORTED Distinct 运算符的变体。GROUP SORTED COUNT AGGREGATE 运算符要求输入集按 group by 列排序。其算法与 GROUP SORTED Distinct 的算法很类似。

从子运算符读取行。如果该行是新矢量的开头,则高速缓存其分组列, 并初始化集合结果。

如果行属于当前正在被处理的组,则对集合结果应用集合函数。当子运 算符返回新组开头的一行或 End Of Scan 时,当前矢量及其集合值返回 到父运算符。

在处理完整个组后会返回 GROUP SORTED COUNT AGGREGATE 运算符中的 第一行,而在开始处理新组时会返回 GROUP SORTED Distinct 运算符 中的第一行。以下示例收集所有城市的列表,并指出在每个城市居住的 作者的数目。

select city, total_authors = count(*) from authors

group by city plan "(group_sorted

(sort (scan authors))

)"


QUERY PLAN FOR STATEMENT 1 (at line 1).

Optimized using the Abstract Plan in the PLAN clause.


STEP 1

The type of query is SELECT.


3 operator(s) under root ROOT:EMIT Operator (VA = 3)

|GROUP SORTED Operator (VA = 2)

| Evaluate Grouped COUNT AGGREGATE.

|

| |SORT Operator (VA = 1)

| | Using Worktable1 for internal storage.

| |

|

|

|

SCAN Operator (VA = 0)

|

|

|

FROM TABLE

|

|

|

authors

|

|

|

Table Scan.

|

|

|

Forward Scan.

|

|

|

Positioning at start of table.

|

|

|

Using I/O Size 2 Kbytes for data pages.

|

|

|

With LRU Buffer Replacement Strategy for

data pages.

在上述查询计划中, authors 的扫描不按分组顺序返回行。 SORT 运算符用 于按分组列 city 对数据流排序。此时,GROUP SORTED COUNT AGGREGATE 运算符可用于计算 count 集合。

GROUP SORTED COUNT AGGREGATE 运算符的 showplan 输出报告正被使用 的集合函数,如下所示:

| Evaluate Grouped COUNT AGGREGATE.


HASH VECTOR AGGREGATE 运算符

HASH VECTOR AGGREGATE 运算符是阻塞运算符。必须处理完来自子运 算符的所有行后,才能将来自 HASH VECTOR AGGREGATE 运算符的第一 行返回给其父运算符。除此之外,其算法与 HASH Distinct 运算符的 算法类似。

从子运算符获取行。在查询的分组列中散列各行。搜索散列桶以查看是 否已存在矢量。

如果 group by 值不存在,则添加矢量,并使用第一行初始化集合值。如 果 group by 值确实存在,则将当前行聚合到现有值。以下示例收集所有 城市的列表,并指出在每个城市居住的作者的数目。


select city, total_authors = count(*) from authors

group by city

QUERY PLAN FOR STATEMENT 1 (at line 1). STEP 1

The type of query is SELECT.


2 operator(s) under root ROOT:EMIT Operator (VA = 2)

|HASH VECTOR AGGREGATE Operator (VA = 1)

| GROUP BY

| Evaluate Grouped COUNT AGGREGATE.

| Using Worktable1 for internal storage.

| Key Count: 1

|

| |SCAN Operator (VA = 0)

| | FROM TABLE

| | authors

| | Table Scan.

| | Forward Scan.

| | Using I/O Size 2 Kbytes for data pages.

| | With LRU Buffer Replacement Strategy for data pages.

在上述查询计划中, HASH VECTOR AGGREGATE 运算符从其子运算符读 取所有行,其子运算符扫描 authors 表。检查每一行以查看是否已存在 当前 city 值的桶项。如果不存在,则添加具有新的 city 分组值的散列项 行,并将计数结果初始化为 1。如果已有新行的 city 值的散列项,则应 用集合函数。在这种情况下,将增加计数结果。

showplan 输出显示专用于 HASH VECTOR AGGREGATE 运算符的 group by 消 息,然后输出分组集合消息:

| Evaluate Grouped COUNT AGGREGATE.

showplan 输出报告用于存储溢出的组和未处理的行的工作表:

| Using Worktable1 for internal storage.


GROUP INSERTING


GROUP INSERTING 是阻塞运算符。必须处理完来自子运算符的所有行 后,才能从 GROUP INSERTING 返回第一行。

group by 子句中, GROUP INSERTING 限制为 31 或更少的列。该运算 符以创建带有分组列的聚簇索引的工作表开始。因为每行是从子运算符 获取的,因此将根据分组列完成在工作表中进行查找的操作。如果未找 到行,则插入行。这样可有效创建新的组以及初始化其集合值。如果找 到行,将根据计算的新值来更新新的集合值。 GROUP INSERTING 运算 符返回按分组列排序的行。

select city, total_authors = count(*) from authors

group by city plan

'(group_inserting (i_scan auidind authors ))'

QUERY PLAN FOR STATEMENT 1 (at line 1).

Optimized using the Abstract Plan in the PLAN clause.


STEP 1

The type of query is SELECT.


2 operator(s) under root

|ROOT:EMIT Operator (VA = 2)

|

| |GROUP INSERTING Operator (VA = 1)

| | GROUP BY

| | Evaluate Grouped COUNT AGGREGATE

| | Using Worktable1 for internal storage.

| |

| | |SCAN Operator (VA = 0)

| | | FROM TABLE

| | | authors

| | | Table Scan.

| | | Forward Scan.

| | | Positioning at start of table.

| | | Using I/O Size 2 Kbytes for data pages.

| | | With LRU Buffer Replacement Strategy for data pages.

在上述示例中,group inserting 运算符是从构建带有聚簇索引键列 city 的 工作表开始的。 group inserting 运算符继续清除 authors 表。对于每一行, 均根据 city 值来完成查找。如果集合工作表中没有包含当前 city 值的行, 将插入行。这将为包含初始化 count 值的当前 city 值创建新组。如果为 当前 city 值找到行,将执行计算以增加 COUNT AGGREGATE 值。


compute by 消息


select city from authors order by city


处理在 EMIT 运算符中已完成,并要求按查询中的任何 order by 要求对 EMIT 运算符的输入数据流进行排序。处理方式类似于在 GROUP SORTED AGGREGATE 运算符中的处理方式。

检查从子运算符读取的每一行以查看它是不是新组的开头。如果不是, 则根据查询的请求组应用适当的集合函数。如果开始一个新组,则当前 组及其集合值将返回到用户。然后,将开始新组,并根据新行的值初始 化其集合值。以下示例收集所有城市的有序列表,并在城市列表之后报 告每个城市的条目的数目。

compute count(city) by city

QUERY PLAN FOR STATEMENT 1 (at line 1). STEP 1

The type of query is SELECT.


2 operator(s) under root Emit with Compute semantics ROOT:EMIT Operator (VA = 2)

|SORT Operator (VA = 1)

| Using Worktable1 for internal storage.

|

| |SCAN Operator (VA = 0)

|

|

FROM TABLE

|

|

authors

|

|

Table Scan.

|

|

Forward Scan.

|

|

Positioning at start of table.

|

|

Using I/O Size 2 Kbytes for data pages.

|

|

With LRU Buffer Replacement Strategy for

data pages.

在上述示例中, EMIT 运算符的输入数据流按 city 属性排序。针对每一 行,增加 compute by 的计数值。当获取新的 city 值后,当前的 city 值和 关联的计数值将返回给用户。新 city 值将成为新的 compute by 分组值, 其计数将初始化为 1




--------------------------------------华丽的分割线-------------------------------------------------------------------------
之前就已经研发成功了能够从Sybase SQL Anywhere的DB文件中恢复数据的工具:ReadASADB。
此工具支持ASA v5.0,v6.0,v7.0,v8.0,v9.0,v10.0,v11.0,v12.0等版本。
恢复Sybase SQL Anywhere的工具在国内应该算首创。

ReadASADB功能
能够从损坏的SQL Anywhere数据文件(.db)和UltraLite数据文件(.udb)上提取数据的非常规恢复工具

  1. 适用于所有的SQL Anywhere版本    包括:5.x,6.x,7.x,8.x,9.x,10.x,11.x,12.x
  2. 适用于所有的UltraLite版本
  3. 能够恢复出来表结构和数据
  4. 能够恢复自定义数据类型
  5. 能够恢复存储过程等对象的语法
  6. 能够导出到目标数据库
  7. 能够导出到SQL文件并生成导入脚本
  8. 支持多种字符集  包括:cp850、cp936、gb18030、utf8等
  9. 能够恢复未加密或者简单加密类型的数据
  10. 简单易用
  11. 限制:不支持AES加密的数据文件
请参考:研发成功了从Sybase SQL Anywhere的DB文件上恢复数据的工具
            SQL Anywhere数据库非常规恢复工具ReadASADB使用介绍

ReadASADB适用场景

各种误操作:

  1. 误截断表(truncate table)
  2. 误删除表(drop table)
  3. 错误的where条件误删数据
  4. 误删除db或log文件
  5. 误删除表中的字段

本工具的应用场景:

1.因为物理磁盘故障、操作系统、系统软件方面或者掉电等等原因导致的Sybase SQL Anywhere数据库无法打开的情况;
2.误操作,包括truncate table,drop table,不正确的where条件导致的误删除等;
Sybase SQL Anywhere无法打开时,比较常见的错误是:Assertion failed。
如:
1、Internal database error *** ERROR *** Assertion failed:201819 (8.0.1.2600) Checkpoint log: invalid bitmap page -- transaction rolled back
2、Internal database error *** ERROR *** Assertion failed:201819 (8.0.1.2600) Page number on page does not match page requested -- transaction rolled back
3、Internal database error *** ERROR *** Assertion failed:200502 (9.0.2.2451) Checksum failure on page 23 -- transaction rolled back
4、File is shorter than expected
5、Internal database error *** ERROR *** Assertion failed: 201116 Invalid free list index page found while processing checkpoint log -- transaction rolled back
6、*** ERROR *** Assertion failed: 51901 Page for requested record not a table page or record not present on page等等。
+-------------------------------------华丽的分割线-------------------------------------------------------------------------