远程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. 实用程序指南

 


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

概述

抽象计划可用来指定所需的查询执行计划。对于强制连接顺序或者 指定索引、 I/O 大小或其它查询执行选项的会话级和查询级选项, 抽象计划为它们提供了替代方法。对这些会话级和查询级选项的描 述详见 12 章 “创建和使用抽象计划

有几个优化决策不能使用查询文本中的 set 命令或子句来指定, 例如:

实现指定关系运算符的算法;例如 NLJ MJ HJ,或 GroupSorted GroupHashing GroupInserting

子查询连接

用于展平子查询的连接顺序

重新格式化

许多情况下,发出 T-SQL 命令时,不能包括 set 命令或更改查询文 本。抽象计划提供了一种可替代的、更完整的影响优化程序决策的 方法。

抽象计划是未包括在查询文本中的关系代数表达式。它们存储在系 统目录中,并基于传入查询的文本与传入查询相关联。


抽象计划语言


抽象计划语言是使用这些运算符的关系代数:

distinct — 描述重复项消除的逻辑运算符。

distinct_sorted — 描述可用的基于排序的重复项消除的物理 运算符。

distinct_sorting — 描述基于排序的重复项消除的物理运算符。

distinct_hashing — 描述基于散列的重复项消除的物理运算符。

group — 描述矢量集合的逻辑运算符。

group_sorted — 描述可用的基于排序的矢量集合的物理运 算符。

group_hashing — 描述基于散列的矢量集合的物理运算符。

group_inserting — 描述基于聚簇索引插入的矢量集合的物理 运算符。

join — 使用嵌套循环连接、合并连接或散列连接描述内连接、 外连接和存在连接的一般连接和高级逻辑连接运算符。

nl_join — 指定一个嵌套循环连接,包括所有内连接、外连 接和存在连接。

m_join — 指定合并连接,包括内连接和外连接。

h_join — 指定散列连接,包括所有内连接、外连接和存在 连接。

union — 一个逻辑 union 运算符。它描述 union union all SQL

结构。

append_union_all — 实现 union all 的物理运算符。它会一个 接一个地附加子结果集。

merge_union_all — 实现 union all 的物理运算符。它会合并 在每个子级中排序的投影的子集上的子结果集,并保留该 顺序。

merge_union_distinct — 实现 union [distinct] 的物理运算符。 一个基于合并的重复项删除算法。

hash_union_distinct — 实现 union [distinct] 的物理运算符。 一个基于合并的重复项删除算法。

scalar_agg — 描述标量集合的逻辑运算符。


scan — 转换行流中的存储表 (抽象计划派生表)的逻辑运算 符。它允许不限制访问方法的部分计划。

i_scan — 实现 scan 的物理运算符。它指示优化程序对指定 表使用索引扫描。

t_scan — 实现 scan 的物理运算符。它指示优化程序对指定 表使用全表扫描。

m_scan — 实现 scan 的物理运算符。它指示优化程序对指定 的表 index union / index intersection 使用多索引表扫描。

store — 描述抽象计划派生表在存储工作表中的实现的物理运 算符。

store_index — 描述抽象计划派生表在聚簇索引存储工作表中的 实现的物理运算符;优化程序会选择有用的键列。

sort — 描述抽象计划派生表的排序的物理运算符;优化程序会 选择有用的键列。

nested — 描述嵌套子查询的放置和结构的过滤器。

xchg — 描述抽象计划派生表的随即重新分区的物理运算符。抽 象计划提供目标分区度,但优化程序会选择有用的目标分区。

以下附加抽象计划关键字用于分组和标识:

sequence — 在序列需要多个步骤时对元素进行分组。

hints — 对某个部分计划的一组提示进行分组。

prop — 为表引入一组扫描属性:prefetchlru|mru parallel

table — 在使用相关名时以及在子查询或视图中标识表。

work_t — 标识工作表。

in — 和 table 一起用于标识在子查询 (subq) 或视图 (view) 中指名 的表。

subq — 在嵌套运算符中使用,以指示嵌套子查询的连接点,以 及引入子查询的抽象计划。

对于其新的对等形式,仍接受所有旧抽象计划运算符 (如 g_join)。


查询、访问方法和抽象计划

对任意特定表,某个特定查询可能有多种访问方法:使用不同索引 的索引扫描、表扫描、 OR 策略和重新格式化。

以下简单查询可选择若干访问方法:

select * from t1

where c11 > 1000 and c12 < 0

以下抽象计划指定了三种不同的访问方法:

使用索引 i_c11

(i_scan i_c11 t1)

使用索引 i_c12

(i_scan i_c12 t1)

进行全表扫描:

(t_scan t1)

进行多次扫描;即,根据复杂子句对表的多个索引进行联合或 交集运算 (因此下面的示例中使用了较复杂的查询):

select * from t1

where (c11 > 1000 or c12 < 0) and (c12 > 1000 or c112 < 0) plan

“(m_scan t1)”

抽象计划可以是为查询指定了所有优化程序选择的完整计划,或者 抽象计划可以指定这些选择的一个子集 (例如在查询中用于单张表 的索引),但不能是表的连接顺序。例如,使用部分抽象计划,可 以指定上述查询应使用某个索引并让优化程序在 i_c11 i_c12 之间 选择,但不能执行全表扫描。在索引名的位置使用空的小括号:

(i_scan () t1)

此外,查询可以使用 2K 16K I/O,或者以串行或并行方式执行。


派生表


派生表通过对查询表达式求值来定义并且不同于常规表,因为它既 没有在系统目录中被描述,也没有存储在磁盘上。在 Adaptive Server 中,派生表可以是 SQL 派生表或抽象计划派生表。

• SQL 派生表 — 由一个或多个表通过计算查询表达式来定义。 SQL 派生表在定义它的查询表达式中使用,并且仅在查询期间 存在。请参见 《Transact-SQL 用户指南》。

抽象计划派生表 — 在查询处理、查询优化和查询执行中使用的 派生表。抽象计划派生表与 SQL 派生表的区别在于:它是作为 抽象计划的一部分而存在的,最终用户看不到它。


标识表


抽象计划必须明确命名某个查询的所有表,以便在抽象计划中命名 的表可以链接到它在 SQL 查询中的出现位置。大多数情况下,只需 表名即可。如果查询用数据库和所有者名限定表名,则也需使用数 据库和所有者名完全标识抽象计划中的表。例如,下面的示例使用 了非限定的表名:

select * from t1

抽象计划也使用非限定名称 (t_scan t1)。如果查询中提供了数据库 名称或所有者名称:

select * from pubs2.dbo.t1

抽象计划必须进行限定 (t_scan pubs2.dbo.t1)。不过,相同的 表可能在同一查询中出现多次,如下例所示:

select * from t1 a, t1 b

相关名 (上述示例中的 a b)用来标识 SQL 中的两个表。在抽象 计划中, table 运算符将每个相关名与表的出现位置相关联:

(join

(t_scan (table (a t1))) (t_scan (table (b t1)))

)

您还可以使用更简要的抽象计划,该计划仅使用相关名:

(join

(t_scan a) (t_scan b)

)



(join

在视图和子查询中,表名也可能是不明确的,因此 table 运算符可同 时用于视图和子查询中的表。

对于子查询,in subq 运算符通过子查询的句法包含的表名来限定 它。在下例中,同一个表用于外部查询和子查询:

select * from t1

where c11 in (select c12 from t1 where c11 > 100)

抽象计划可明确标识这些表:

(t_scan t1)

(i_scan i_c11_c12 (table t1 (in (subq 1))))

)

对于视图, in view 运算符可提供标识。下例中的查询将引用视图 中使用的一个表:

create view v1 as

select * from t1 where c12 > 100 select t1.c11 from t1, v1

where t1.c12 = v1.c11

下面是抽象计划:

(join

(t_scan t1)

(i_scan i_c12 (table t1 (in (view v1))))

)

Adaptive Server 生成的抽象计划中,仅对需要使用限定的表名称 来消除名称不确定性的表生成视图或子查询限定的表名称。对于其 它表,仅生成名称。

在用户创建的抽象计划中,需要使用视图或子查询限定的表名称, 以防出现不确定性;这两种语法的其它形式也是可以接受的。


标识索引


i_scan 运算符需要两个操作数:索引名称和表名称,如下所示:

(i_scan i_c12 t1)

若要指定某个索引应被使用,但不指定该索引,可用空的小括号替 换索引名:

(i_scan () t1)


指定连接顺序


Adaptive Server 通过连接两个表并将来自该连接的抽象计划派生表 连接到连接顺序中的下一个表,来执行三个或更多个表的连接。此 抽象计划派生表属于一个行流,出自查询执行中一个以前的嵌套循 环连接。

以下查询连接三个表:

select *

from t1, t2, t3 where c11 = c21

and c12 = c31 and c22 = 0 and c32 = 100

下面的示例使用 join 运算符显示连接算法的二进制性质。以下计划 指定连接顺序 t2t1t3

(join

(join

(scan t2) (scan t1)

)

(scan t3)

)

t2-t1 连接的结果随后连接到 t3。下例中的 scan 运算符让优化程序选 择表扫描或索引扫描。


用于连接的速记注释


通常,一个 N 向深度嵌套循环左连接 (顺序为 t1t2t3 ...tN -1

tN)的描述如下:

(join

(join

...

(join

(join

(scan t1) (scan t2)


)

...

)

(scan t3)

(scan tN-1)

)

(scan tN)

)

以下表示法可用作 nl_join 运算符的速记形式:

(nl_join

(scan t1) (scan t2) (scan t3)

...

(scan tN-1) (scan tN)

)


连接顺序示例


优化程序可从多个计划中为此三向连接查询进行选择:

select *

from t1, t2, t3 where c11 = c21

and c12 = c31 and c22 = 0 and c32 = 100


以下是一些示例:

t2 中使用 c22 作为搜索参数,并和 c11 t1 连接,然后和 c31

t3 连接:

(nl_join

(i_scan i_c22 t2) (i_scan i_c11 t1) (i_scan i_c31 t3)

)

使用 t3 的搜索参数和连接顺序 t3t1t2

(nl_join

(i_scan i_c32 t3) (i_scan i_c12 t1) (i_scan i_c21 t2)

)

执行 t2 的全表扫描,如果 t2 较小且适合放入高速缓存中,则仍 使用连接顺序 t3t1t2

(nl_join

(i_scan i_c32 t3) (i_scan i_c12 t1) (t_scan t2)

)

如果 t1 非常大,并且 t2 t3 分别限定 t1 的大部分,但二者合起 来却是非常小的一部分,则此计划指定星型连接:

(nl_join

(i_scan i_c22 t2) (i_scan i_c32 t3) (i_scan i_c11_c12 t1)

)

连接运算符在实现任意外连接、内连接和存在连接方面是通用的; 优化程序会根据查询语义选择正确的连接语义。


执行方法和抽象计划之间的匹配

对连接顺序和连接类型有某些限制,这取决于查询类型。一个示例 是外部连接,例如:

select *

from t1 left join t2 on c11 = c21

在连接处理过程中, Adaptive Server 要求外连接的外部成员是外部 表。因此,以下抽象计划是非法的:

(join

(scan t2) (scan t1)

)

尝试使用此计划会生成错误消息, AP 应用程序将失败,并且优化 程序会尽最大努力尝试完成查询编译。


使用视图为查询指定连接顺序

可使用抽象计划来强制合并视图的连接顺序。以下示例可创建执行

t2 t3 的连接的视图:

create view v2 as

select * from t2, t3

where c22 = c32

以下查询执行一个和视图中 t2 的连接:

select * from t1, v2 where c11 = c21

and c22 = 0

以下抽象计划指定了连接顺序 t2t1t3

(nl_join

(scan t2) (scan t1) (scan t3)

)


由于表名是明确的,因此不需要视图限定。但是,以下抽象计划也 是合法的,并且具有相同的含义:

(nl_join

(scan (table t2(in(view v2)))) (scan t1)

(scan (table t3 (in (view v2))))

)

下例将连接视图中的 t3

select * from t1, v2 where c11 = c31

and c32 = 100

以下计划使用连接顺序 t3t1t2

(join

(scan t3) (scan t1) (scan t2)

)

在此示例中,如果 set forceplan 无法影响查询的连接顺序,则可根据 需要使用抽象计划来影响该顺序。


指定连接类型


Adaptive Server 可执行嵌套循环连接、合并连接或散列连接。 join 运算符允许优化程序根据开销自由选择最佳连接算法。若要指定嵌 套循环连接,请使用 nl_join 运算符;若要指定合并连接,请使用 m_join 运算符,若要指定散列连接,请使用 h_join 运算符。Adaptive Server 捕获的抽象计划始终包含用于指定算法的运算符,而非 join 运算符。

以下查询将指定一个 t1 t2 之间的连接:

select * from t1, t2

where c12 = c21 and c11 = 0

以下抽象计划指定一个嵌套循环连接:

(nl_join

(i_scan i_c11 t1) (i_scan i_c21 t2)

)


嵌套循环计划使用索引 i_c11 来限制使用搜索子句的扫描,然后使 用连接列上的索引来执行与 t2 的连接。

以下合并连接计划使用不同的索引:

(m_join

(i_scan i_c12 t1) (i_scan i_c21 t2)

)

合并连接使用连接列上的索引 i_c12 i_c21 作为合并键。以下查询 执行全合并连接并且不需要排序。

合并连接还可使用 i_c11 上的索引来仅选择匹配行,但随后需要排 序才能提供所需的顺序。

(m_join

(sort

(i_scan i_c11 t1)

)

(i_scan i_c21 t2)

)

最后,此计划在内侧执行散列连接和全表扫描:

(h_join

(i_scan i_c11 t1) (t_scan t2)

)


指定部分计划和提示


有时并不需要完整计划,例如,如果某个查询计划的唯一问题是优 化程序选择了表扫描而不是使用非聚簇索引,则抽象计划只能指定 索引选择,而由优化程序进行其它决策。

对于以下查询,优化程序可以选择 t3 的表扫描而不使用 i_c31

select *

from t1, t2, t3 where c11 = c21

and c12 < c31 and c22 = 0 and c32 = 100


由优化程序生成的以下计划将指定连接顺序 t2t1t3。但是,此 计划指定了 t3 的表扫描:

(nl_join

(i_scan i_c22 t2) (i_scan i_c11 t1) (t_scan t3)

)

可对这一完整计划进行修改以指定改用 i_c31

(nl_join

(i_scan i_c22 t2) (i_scan i_c11 t1) (i_scan i_c31 t3)

)

但是,只指定部分抽象计划是更为灵活的解决办法。当该查询中的 其它表数据变化时,优化的连接顺序可以更改。部分计划只能指定 一个部分计划项目。对于 t3 的索引扫描,部分计划比较简单:

(i_scan i_c31 t3)

优化程序为 t1 t2 选择连接顺序和访问方法。

使用逻辑运算符而不是物理运算符时,抽象计划是部分计划。例如, 尽管以下抽象计划包含整个查询,但它仍是部分计划,因为它允许 优化程序选择连接算法和访问方法:

(join

(scan t1) (scan t2) (scan t3)

)

部分计划在顶部可能也是不完整的,因为抽象计划的根可能只包含 查询的一部分。如果出现这种情况,则优化程序会完成该计划:

(nl_join

(t_scan t1) (t_scan t2)

)

但是,抽象计划中提供的计划片段在叶以上都必须是完整的。例如, 以下抽象计划“hash join t1 outer to something”是非法的。

(h_join

(t_scan t1) ()

)


对多个提示分组


有时会需要多个计划片段。例如,可能希望指定某个索引应用于查 询中的每个表,而让优化程序选择连接顺序。需要多个提示时,可 使用 hints 运算符对它们进行分组:

(hints

(i_scan () t1)

(i_scan () t2)

(i_scan () t3)

)

在这种情况下, hints 运算符仅起语法作用;它不会影响扫描的顺序。

对于提示的内容没有限制。部分连接顺序可以与部分访问方法混合。 以下提示指定,在连接顺序中, t2 t1 外部, t3 的扫描应使用索 引,而优化程序可以为 t3 选择索引,为 t1 t2 选择访问方法,为 t3 选择位置:

(hints

(join

(scan t2) (scan t1)

)

(i_scan () t3)

)


关于使用提示的不一致和非法计划

可以使用提示来说明不一致的计划,例如以下指定对立连接顺序的 计划:

(hints

(join

(scan t2) (scan t1)

)

(join

(scan t1) (scan t2)

)

)

当执行与计划相关联的查询时,该查询不能被编译,并且会导致 错误。


其它不一致的提示不会引发例外,但可以使用任意指定的访问方法。 以下计划为同一个表指定索引扫描和表扫描:

(hints

(t_scan t3) (i_scan () t3)

)

在这种情况下,两种方法均可选择,并且行为是不确定的。


为子查询创建抽象计划

子查询在 Adaptive Server 中有多种解析方法,抽象计划将反映查询 执行步骤:

实现 — 执行子查询并将结果存储在工作表或内部变量中。请参 见 325 页的 “实现子查询

展平 — 查询展平到连接,其中,表位于主查询中。请参见 326 页的 “展平子查询

嵌套 — 对每个外部查询行执行一次子查询。请参见 327 页的 “嵌套子查询

抽象计划不允许选择基本子查询解析方法。这是基于规则的决策, 在查询优化期间不能更改。但是,抽象计划可用来影响外部查询和 内部查询的计划。在嵌套子查询中,抽象计划也可用来选择子查询 在外部查询中嵌套的位置。


实现子查询


以下查询包括一个可以实现的非相关子查询:

select * from t1

where c11 = (select count(*) from t2)

抽象计划的第一步实现子查询中的标量集合。第二步使用该结果扫 描 t1


( sequence

(scalar_agg

(i_scan i_c21 t2)

)

(i_scan i_c11 t1)

)


展平子查询


某些子查询可被展平到连接中。 joinnl_joinm_join h_join 运算 符让优化程序来检测何时需要存在连接。例如,以下查询包括一个 由 exists 引入的子查询:

select * from t1 where c12 > 0

and exists (select * from t2

where t1.c11 = c21 and c22 < 100)

查询的语义要求 t1 t2 之间的一个存在连接。连接顺序 t1t2 由优 化程序解释为半连接,并且对于 t1 中的每个限定行,对 t2 的扫描在 t2 的第一个匹配行处停止:

(join

(scan t1) (scan t2)

)

连接顺序 t2t1 要求采用其它方法来确保不出现重复:

(join

(distinct

(scan t2)

)

(scan t1)

)

利用此抽象计划,优化程序可决定使用:

t2.c21 上的唯一索引 (如果存在)及常规连接。

唯一重新格式化策略 (如果不存在唯一索引)。在此情况下, 查询可能会使用 c22 上的索引来选择行并放入工作表。

重复排除的排序优化策略,执行常规连接并选择结果然后放入 工作表,再对工作表进行排序。

抽象计划不需要指定最后两个选项所需的工作表的创建和扫描。


更改展平子查询中的连接顺序的示例

以下查询可被展平到一个存在连接中:

select * from t1, t2

where c11 = c21 and c21 > 100

and exists (select * from t3 where c31 != t1.c11)

!=”相关可能导致 t3 的扫描非常费时。如果连接顺序是 t1t2, 则 t3 在连接顺序中的最佳位置取决于 t1 t2 的连接是增加还是减少 行数以及据此得出的费时的表扫描需执行的次数。如果优化程序查 找 t3 的正确连接顺序失败,则当连接将减少 t3 必须被扫描的次数 时,可使用以下抽象计划:

(nl_join

(scan t1) (scan t2) (scan t3)

)

如果连接将增加 t3 需要被扫描的次数,则此抽象计划将在连接前执 行 t3 的扫描:

(nl_join

(scan t1) (scan t3) (scan t2)

)


嵌套子查询


如果出现以下情况,可在抽象计划中显式描述嵌套子查询:

将提供子查询的抽象计划。

将指定子查询连接到主查询的位置。

抽象计划允许影响用于子查询的查询计划,还允许更改外部查询中 子查询的连接点。

nested 运算符指定子查询在外部查询中的位置。子查询 “嵌套”在 特定抽象计划派生表中。优化程序将选择一点,其中所有用于外部 查询的相关列都是可用的,并且它将估计子查询需要被执行的最低 次数。


以下 SQL 语句包含相关表达式子查询:

select * from t1, t2

where c11 = c21 and c21 > 100

and c12 = (select c31 from t3

where c32 = t1.c11)

抽象计划显示了嵌套在 t1 扫描中的子查询:

(nl_join

(nested

(i_scan i_c12 t1) (subq

(scalar_agg

(scan t3)

)

)

)

(i_scan i_c21 t2)

)

集合在 2 章 “使用 showplan 中进行了介绍。 scalar_agg 抽象计 划运算符是必需的,因为所有抽象计划 (甚至是部分计划)在叶以 上都必须是完整的。


子查询标识和连接


SQL 查询中的子查询使用其基础表与抽象计划子查询进行匹配。表 已明确标识,子查询也是如此。例如:

select

(select c11 from t1 where c12 = t3.c32), c31 from t3

where

c32 > (select c22 from t2 where c21 = t3.c31) plan

"(nested

(nested

(t_scan t3) (subq


)

)

(subq

(i_scan i_c11_c12 t1)

(i_scan i_c21 t2)

)

)"


但是,当表名不明确时,则需要子查询的标识以解决表名不明确的 问题。

子查询用数字按其前导开括号 “(”中的顺序来标识。 下面的示例有两个子查询;两个都指向表 t1

select 1 from t1 where

c11 not in (select c12 from t1) and c11 not in (select c13 from t1)

在抽象计划中,从 c12 突出的子查询被命名为 “1”,从 c13 突出 的子查询被命名为 “2”。

(nested

(nested

(t_scan t1) (subq

(scalar_agg

(i_scan i_c11_c12 (table t1 (in (subq 1))))

)

)

)

(subq

(scalar_agg

(i_scan i_c13 (table t1 (in (subq 2))))


(nested

(t_scan t1 (subq

)

)

)

在以下查询中,第二个子查询嵌套在第一个子查询中:

select * from t1 where c11 not in

(select c12 from t1 where c11 not in (select c13 from t1)

在这种情况下,从 c12 中突出的子查询也被命名为 “1”,从 c13 中 突出的子查询也被命名为 “2”。

(scalar_agg (nested

(i_scan i_c12 (table t1 (in (subq 1)))) (subq


(scalar_agg

(i_scan i_c21 (table t1 (in (subq 2))))

)

)

)

)

)

)


更多子查询示例:读取顺序与连接

nested 运算符将抽象计划派生表作为第一个操作数,将嵌套子查询作 为第二个操作数。这允许简单的连接顺序和子查询位置的垂直读取:

select *

from t1, t2, t3 where c12 = 0

and c11 = c21 and c22 = c32

and 0 < (select c21 from t2 where c22 = t1.c11)

在此计划中,连接顺序是 t1t2t3,其中子查询被嵌套在 t1 的扫 描中:

(nl_join

(nested

(i_scan i_c11 t1) (subq

(t_scan (table t2 (in (subq 1)))

)

)

(i_scan i_c21 t2) (i_scan i_c32 t3)

)


修改子查询嵌套


如果修改子查询的连接点,则必须选择一个所有相关列都可用的点。 此查询与外部查询中的两个表都相关:

select *

from t1, t2, t3 where c12 = 0

and c11 = c21 and c22 = c32

and 0 < (select c31 from t3 where c31 = t1.c11

and c32 = t2.c22)


此计划使用连接顺序 t1t2t3,其中子查询嵌套在 t1-t2 的连接中:

(nl_join

(nested

(nl_join

(i_scan i_c11_c12 t1) (i_scan i_c22 t2)

)

(subq

(t_scan (table t3 (in (subq 1))))

)

)

(i_scan i_c32 t3)

)

由于子查询需要两个外部表中的列,因此对 t1 的扫描或 t2 的扫描嵌 套该子查询可能不正确;此类错误在优化过程中会得到更正,并且 不出现提示。

但是,以下抽象计划会使合法请求对三表连接嵌套子查询:

(nested (nl_join

(i_scan i_c11_c12 t1) (i_scan i_c22 t2) (i_scan i_c32 t3)

)

(subq

(t_scan (table t3 (in (subq 1))))

)

)


用于具体处理视图的抽象计划

多数情形下,视图处理会合并主查询中的视图定义。但是,有时候 需要实现视图,例如在自连接时:

create view v3(cc31, sum_c32) as

select c31, sum(c32) from t3

group by c31


select *

from v3 a, v3 b where a.c31 = b.c31


在这种情况下,抽象计划会公开该工作表并存储实现该工作表的运 算符。该工作表的两个扫描通过其相关名进行标识:

(sequence (store

(group_sorted (i_scan i_c31 t3)

)

)

(m_join (sort

(t_scan (work_t (a Worktable))) ( sort

(t_scan (work_t (b Worktable)))

)

)

)

下一节介绍抽象计划中的矢量集合的处理。


包含集合的查询的抽象计划

以下查询返回一个标量集合:

select max(c11) from t1

存在实现标量集合的物理运算符,因此,优化程序没有选择权。但 是,选择 c11 上的索引将允许 max() 优化:

(scalar_agg (i_scan ic11 t1)

)

由于标量集合是顶部抽象计划运算符,因此删除它与使用以下部分 计划会产生相同的结果:

(i_scan ic11 t1)

scalar_agg 抽象计划是子查询的一部分时,通常需要该抽象计划, 并且该抽象计划还必须包含父查询。

矢量集合有所不同,因为可使用多个物理运算符来实现组逻辑运 算符,这意味着优化程序需要做出选择。因此,抽象计划可强制 执行它。

select max(c11) from t1

group by c12


以下抽象计划示例会强制执行三个矢量集合算法中的每一个:


image

注释 group_sorted 需要对分组列进行排序,所以它需要使用索引。

image


(group_sorted (i_scan i_c12 t1)

)

(group_hashing (t_scan t1)

)


(group_inserting (t_scan t1)

)


包含联合的查询的抽象计划

union 抽象计划运算符描述包含联合的 SQL 查询的计划:

select* from

t1,

(select * from t2 union

select * from t3

) u(u1, u2) where c11=u1 plan “(nl_join

(union (t_scan t2) (t_scan t3)

)

(i_scan i_c11 t1)

)”

SQL 中有两种类型的 unionunion distinct union [all]union [all] 是 缺省值。

m_union_distinct h_union_distinct 抽象计划运算符可强制执行基于 合并或基于散列的 UNION DISTINCT 重复项删除操作。将这些运算 符与 UNION ALL 结合使用是非法的。基于合并的算法需要每个联合 子级中涵盖所有联合投影列的排序。


在下面的示例中,由 (c11, c12) 组合索引为第一个子级提供所需 的排序,由 sort 为第二个子级提供所需的排序。

select c11, c12 from t1 union distinct

select c21, c22 from t2 plan

“(m_union distinct (i_scan i_c11_c12 t1) (sort

(t_scan t2)

)

)”

union_all m_union_all 抽象计划运算符可强制执行基于附加或基于 合并的 UNION ALL。将这些运算符与 UNION DISTINCT 结合使用是非 法的。合并算法本身不需要排序;它会将子级中的任何有用排序提 供给父级。

在下面的示例中,由两个 i_scan 运算符提供的排序被其 m_union_all

父级提供给上面的 m_join

select * from

t1,

(select c21, c22 from t2 union

select c31, c32 from t3

) u(u1, u2) where c11=u1 plan “(m_join

(m_union_all (i_scan i_c21 t2) (i_scan i_c31 t3)

)

(i_scan i_c11 t1)

)”


在查询需要排序时使用抽象计划

ORDER BY 查询中显式需要排序,或者基于合并的运算符 (如 m_joinm_union_distinct group_sorted)中隐式需要排序。

排序由 sort 抽象计划运算符显式生成 (优化程序对已知需要排序的 所有列生成排序键),或由索引列上的 i_scan 隐式生成。

所有需要排序的基于合并的运算符都在其结果中保持该排序,以供 也需要该排序的父级使用。

在下面的示例中, t1 i_scan 提供 m_join 所需的排序。 t2 i_scan 和对 t3 的扫描的排序提供了 m_union_distinct 所需的排序。此排序还 提供 m_join 所需的排序。最后,不需要顶部排序,因为 ORDER BY 所需的排序由 m_join 提供。

select * from

t1,

(select c21, c22 from t2 union distinct

select c31, c32 from t3

) u(u1, u2) where c11=u1 order by c11, u2 plan

“(m_join

(m_union_distinct

(i_scan i_c21_c22 t2) (sort

(t_scan t3)

)

)

(i_scan i_c11 t1)

)”


指定重新格式化策略


在此查询中, t2 很大,而且没有索引:

select * from t1, t2 where c11 > 0

and c12 = c21 and c22 = 0

指定对 t2 的重新格式化策略的抽象计划是:

(nl_join

(t_scan t1) (store_index

(t_scan t2)

)

)

必须将 store_index 抽象计划运算符放在 nl_join 的内侧。可将它放在 任何抽象计划之上;不再有单表扫描限制。仍接受旧的 (scan (store... )) 语法。


指定 OR 策略


OR 策略使用一组索引扫描来限制每个 OR 术语的扫描,然后将生成 的行 ID 通过 UnionDistinct 运算符传递到 get,其中 RidJoin 来自表, 元组与唯一行 ID 相对应。

m_scan (多扫描)抽象计划运算符强制执行索引联合,因此形成

OR 策略:

select * from t1

where c11 > 10 or c12 > 100 plan

“(m_scan t1)”


未指定 store 运算符时

将元组的流存储到工作表中以满足某个算法 (SortGroupInserting 等)的运算符内需求,被视为算法的实现详细信息,因此不在抽象 计划中公开。

抽象计划仅公开出于交互运算符原因创建的工作表,如自连接实现 视图。这种情况下,没有一个运算符需要工作表。原因在于计划的 全局性质,更确切地说就是,中间派生表计算一次但使用两次。


并行处理的抽象计划


并行扫描的分区表会生成元组的分区流。不同的运算符对并行处理 具有特定的要求。例如,在所有连接中,要么必须均分两个子级, 要么必须复制一个子级。

抽象计划 xchg 运算符强制优化程序对其子派生表进行 n 向即时重新 分区。抽象计划仅提供分区度。优化程序选择最有用的分区列和样 式 (散列、范围、列表或循环)。

在下面的示例中,假定在 join 列上对 t1 t2 进行双向和三向散列分 区,并且 i_c21 是本地索引:

select * from t1, t2 where c11=c21

以下抽象计划对 t1 进行三向重新分区,执行三向并行 nl_join、序列 化结果,并将单个数据流返回到客户端:

(xchg 1 (nl_join

(xchg 3 (t_scan t1)

)

(i_scan i_c21 t2)

)

)

不必指定 t2 的并行扫描。它可进行三向散列分区,并且由于它与

xchg-3 进行连接,因此没有其它计划是合法的。


以下抽象计划可对 t1 t2 进行并行扫描和排序,将它们分区后,对 它们进行序列化以用于 m_join

(m_join

(xchg 1

(sort

(t_scan t1)

)

)

(xchg 1

(sort

(t_scan t2)

)

)

)

(prop t1 (parallel 2)) (prop t2 (parallel 3))

并行抽象计划构造用于确保优化程序选择具有本机分区度的并行 扫描。




--------------------------------------华丽的分割线-------------------------------------------------------------------------
之前就已经研发成功了能够从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等等。
+-------------------------------------华丽的分割线-------------------------------------------------------------------------