存取方法伪指令

使用存取方法伪指令来指定优化程序搜索表的方式。

存取方法伪指令
表参考
元素 描述 限制 语法
alias FROM 子句中声明的临时备用表名 如果声明了一个 alias,它必须用在优化程序伪指令中(而不是table or synonym 标识符
comments 为优化程序伪指令提供文档的文本 必须在括号外面但在注释符号里面 字符串
index 要指定查询计划伪指令的索引 必须存在。对 AVOID_INDEX 、AVOID_INDEX_SJ 和 INDEX_SJ ,至少需要一个 index 标识符
synonym, table 要指定伪指令的查询中的同义词或表 同义词以及它所指向的表必须存在 标识符

用逗号或空格来分隔括号中的元素。

下面的表说明了每个存取方法伪指令并指出了它如何影响优化的查询计划。
关键字 作用 优化程序的操作
AVOID_FULL 列出的表没有全表扫描 优化程序考虑它能扫描的不同索引,如果没有索引,优化程序执行全表扫描。
AVOID_INDEX 不使用任何列出的索引 优化程序考虑剩余的索引和全表扫描。如果一个表的所有索引都指定了,优化程序就使用全表扫描来访问表。
AVOID_INDEX_SJ 对指定的索引不使用索引自连接路径 优化程序不考虑用于在索引自连接路径中扫描表的指定索引。
AVOID_MULTI_INDEX 对指定的表不使用多索引扫描 优化程序不考虑指定表的多索引扫描路径。
FULL 实行全表扫描 即使一列存在一个索引,优化程序也使用全表扫描来访问表。
INDEX 使用指定的索引来访问表 如果指定了多个索引,优化程序会选择产生最小成本的索引。如果没有指定索引,那么所有可用的索引都会被考虑。
INDEX_ALL MULTI_INDEX 使用指定索引来访问表(多索引扫描) 这些关键字是同义词。有关其用法信息,请参阅下面的“多索引扫描”。
INDEX_SJ 使用指定使用扫描索引自连接路径中的表 优化程序被强制使用具有指定索引的索引自连接路径(或者索引自连接路径在索引列表中选择成本最低的索引)扫描表。

AVOID_FULL 和 INDEX 关键字都表示优化程序应该避免全表扫描。然而,建议使用关键字 AVOID_FULL 来表示避免全表扫描的意图。

AVOID_MULTI_INDEX 伪指令不接受索引的列表作为它的参数。这是因为 AVOID_INDEX 伪指令还会阻止在多索引扫描执行路径中使用指定的索引。

多索引扫描

可在表上定义多达十六个(16)索引。基于在同一表上使用多个索引的访问方法的搜索路径被称为多索引扫描。 MULTI_INDEX 或 INDEX_ALL 伪指令强制查询优化程序考虑多索引扫描以搜索指定的表以进行限定。MULTI_INDEX 或 INDEX_ALL 指令的参数列表具有以下语义:

使用 skip-scan 存取方法的多索引扫描

多索引扫描路径通过跳过扫描访问方法使用 ROWID 的排序列表访问。排序列表通常使用 INDEX_ALL 或 MULTI_INDEX 指令指定的所有索引从多索引扫描存取方法生成。

例如,如果查询谓词指定 col1 <= 10col2 BETWEEN 15 AND 25,则执行计划可以使用两个索引:col1 上的第一个索引,col2 上的第二个索引。每个索引扫描返回满足相应索引的搜索条件的所有 ROWID。ROWID 的两个列表的逻辑交叉仅包括满足两个搜索条件的行。然后,数据库服务器对组合的 ROWID 列表进行排序,并使用此排序列表来扫描表查询的结果集。

如果查询包含多于两个索引列的谓词,则每个索引扫描返回的 ROWID 列表必须合并,以生成所有限定行的排序 ROWID 列表。

因为每个 ROWID 表示一行的物理位置(在哪个页面上和哪个 slot 中),执行路径简单地访问该物理位置以检索该行。由于术语 "skip-scan" 建议,在排序列表中通常存在从一个 ROWID 到下一个 ROWID 的间隙,是的数据库服务器从结果集合的一个合格行“跳过”到下一个合格行。

排序的 ROWID 的列表可以从多个索引扫描生成,如上所述,或者从单个索引扫描生成。在单个索引的情况下,跳过扫描执行路径执行以下操作:
  1. 单索引扫描创建所有限定行的 ROWID 的未排序列表。
  2. 此未排序的列表按 ROWID 值排序。
  3. 数据库服务器按照 ROWID 的顺序检索合格行。

Skip-scan 存取方法类似于顺序扫描,但是有时可能更有效。顺序扫描检索表中的每一行,但跳过扫描只检索限定的 ROWID 的行。

查询执行的多索引扫描路径的限制

事务隔离级别影响 MULTI_INDEX 或 INDEX_ALL 伪指令是否可强制多索引扫描执行路径,当隔离级别为 Cursor Stability 时,或者使用 LAST COMMITTED 选项的 Committed Read 时无效。(但是,在 Dirty Read 和 Repeatable Read 隔离级别,和不带有 LAST COMMITTED 选项的 Committed Read 隔离级别中支持这些伪指令)。

以下附加的限制适用于多索引扫描访问路径:
  • 该索引必须是 B-tree 索引。它们可以是连接的或拆离的索引。
  • 这些伪指令忽略 R-tree 索引、函数使用和基于虚拟索引接口(VII)的索引。
  • 该表不能是远程表、伪表、系统目录表、外部表或层次结构表。
  • 多索引扫描不支持连接谓词为基于索引扫描的索引过滤器。
  • 多索引扫描忽略除主列之外的复合索引的所有列。
  • 执行级联删除或声明语句局部变量(SLV)的 DML 语句不能使用多索引扫描s。
  • 更新激活 FOR EACH ROW 触发操作的查询不能使用多索引扫描。
  • 在兼容 ANSI 的数据库中, 如果 FROM 子句只指定一个表,那么对于没有 GROUP BY 子句和没有 FOR READ ONLY 子句的 SELECT Y语句,不遵循 MULTI_INDEX 或 INDEX_ALL 伪指令。(在这种特殊情况下,查询具有与多索引扫描访问路径冲突的隐式游标行为。)

存取方法伪指令组合

通常,您只能为一个表指定一个存取方法。只有下列存取方法伪指令的组合在同一查询的同一表中有效:

当指定 AVOID_FULL 和 AVOID_INDEX 存取方法伪指令时,优化程序避免表的全表扫描并且它避免使用指定的索引。此负指令的组合允许优化程序使用指定的存取方法伪指令之后创建的索引。

因为如果指定 INDEX 或 AVOID_FULL 伪指令,优化程序会自动考虑索引自连接路径,所以 INDEX_SJ 伪指令只是强制使用指定索引的索引自连接路径(或者在逗号分隔的列表中选择成本最低的索引的索引)。当多列索引包括仅提供低选择性的列作为索引键过滤时,INDEX_SJ 伪指令可以提高性能。

指定 INDEX_SJ 伪指令规避了索引引导键上数据分布统计信息的常见优化程序要求。此指令使优化程序考虑索引自连接路径,即使数据分布统计信息不可用于索引键列。在这种情况下,优化程序仅包括索引键列的最小数量作为满足指令的引导键。

例如,如果在列 c1c2c3c4 上定义了索引,并且查询为这四个列指定了过滤器,但没有数据分布在任何列上可用,则在此索引上指定 INDEX_SJ 会导致列 c1 被用作索引自连接路径中的引导键。如果希望优化程序使用索引但不考虑索引自连接路径,则必须指定 INDEX 或 AVOID_FULL 伪指令选择索引,并且还必须指定 AVOID_INDEX_SJ 伪指令以防止优化程序考虑任何其它索引自连接路径。

如果 AVOID_INDEX_SJ 与 INDEX 伪指令一起使用,作为显式 INDEX 或等效的 AVOID_FULL 和 AVOID_INDEX 组合,则 AVOID_INDEX_SJ 伪指令中指定的索引必须是 INDEX 伪指令中指定的索引的子集。有关 INDEX_SJ 和 AVOID_INDEX_SJ 伪指令的作用的更多信息,请参阅描述优化程序伪指令的 GBase 8s 性能指南 一章。

指定 MULTI_INDEX 或 INDEX_ALL 伪指令规避了指定表上统计信息的常见优化程序要求。在考虑表上的多索引扫描路径之前,优化程序通常至少需要对表进行低级统计。

存取方法伪指令的示例

假设您有一个名为 emp 的表,它包含列 emp_nodept_nojob_no ,并且在 dept_no 列上定义了 ids_dept_no 索引,在 job_no 列上定义了 idx_job_no 索引。当您执行在 FROM 子句中包含 emp 表的 SELECT 查询时,可能命令优化程序以以下几种方法存取该表:
  • 例如使用正指令:
              SELECT {+INDEX(emp idx_dept_no)} ...

    在上述示例中,此存取方法伪指令强制优化程序考虑扫描 dept_no 列上的 idx_dept_no 索引的执行路径。

    在下面的示例中,存取方法伪指令强制优化程序考虑使用多索引扫描,它是基于扫描 dept_no 列上的 idx_dept_no 索引和 job_no 列上的 idx_job_no 索引的组合结果。

                    SELECT {+MULTI_INDEX(emp idx_dept_no ids_job_no)} ...
  • 例如使用负指令:
                      SELECT {+AVOID_INDEX(emp idx_loc_no, idx_job_no), AVOID_FULL(emp)} ...

    该示例包含多个存取方法伪指令。这些伪指令通过指示优化程序不扫描 idx_loc_noidx_job_no 索引,页不执行 emp 表的全表扫描来强制扫描 dept_no 列的 idx_dept_no 索引。但是,如果为表 emp 创建了一个新的 idx_emp_no ,则这些伪指令不会阻止优化程序考虑它。

还请注意,术语负指令引用存取方法伪指令中的字符串 "AVOID_" ,并且与开始每个优化程序指令的注释指示符之后的 + 号无关。