Hint 是 SQL 语句中将指令传递给 OceanBase 数据库优化器或服务器的一种注释。通过 Hint 可以使优化器或服务器生成某种特定的计划。 一般情况下,优化器会为用户查询选择最佳的执行计划,不需要用户主动使用 Hint 指定,但在某些场景下,优化器生成的执行计划可能不满足用户的要求,这时就需要用户使用 Hint 来主动指定并生成特殊的执行计划。

Hint 应该少用,仅在您收集了相关表的统计信息并且使用 EXPLAIN PLAN 语句在没有 Hint 的情况下评估了优化器计划之后,才谨慎考虑使用。更改数据库条件以及在后续版本中增强查询性能可能会导致您代码中的 Hint 对性能产生重大影响。

Hint 的使用

一个语句块只能有一个注释包含 Hint,并且该注释必须跟随 SELECTUPDATEINSERTMERGEDELETE 关键字。

以下是 Hint 在语句块注释中的语法格式:

  1. /*+[hint text]*/

Hint 从语法上看是一种特殊的 SQL 注释, 所不同的是在注释的左标记后增加了一个加号(+)。 如果服务器端无法识别 SQL 语句中的 Hint,那么优化器会选择忽略用户指定的 Hint 而使用默认计划所生成逻辑。另外需要指明的是,Hint 只影响优化器所生成的计划的逻辑,而不影响 SQL 语句的语义。

以下是定义 Hint 时需要注意的一些规则:

  • 加号(+)使数据库将注释解释为 Hint 列表。加号必须紧跟在注释左标记符后,不允许有空格。

  • 加号(+)和 Hint 文本之间的空格是可选的。如果注释中包含多个 Hint,则 Hint 间至少用一个空格进行分隔。

  • Hint 包含拼写错误或语法错误时会被忽略。但是,数据库会考虑在同一注释中其他正确指定的 Hint。

  • 不跟随 DELETEINSERTMERGESELECTUPDATE 关键字的 Hint 无效。

  • Hint 的组合相互冲突时 Hint 无效。但是,数据库会在同一注释中考虑其他不冲突的 Hint。

  • 数据库环境使用 PL/SQL 版本 1 时 Hint 无效,例如 Forms 版本 3 触发器。

在 Hint 中定义查询块

您可以通过在许多 Hint 中定义一个可选的查询块名称,以此来指定该 Hint 适用的查询块。使用此语法,允许您在外部查询中指定一个应用于嵌入式视图的 Hint。

查询块参数的语法格式为 @queryblock,其中 queryblock 是在查询中被指定的查询块的标识符。queryblock 标识符可以是系统生成的,也可以是用户自己指定的。当您在查询块中直接指定要应用的 Hint 时,将忽略 @queryblock

  • 系统生成的标识符可以通过对查询使用 EXPLAIN PLAN 生成,预转换查询块的名称可以通过对使用了 NO_QUERY_TRANSFORMATION Hint 的查询运行 EXPLAIN PLAN 生成。

  • 可以使用 QB_NAME 来指定用户自定义的名称。

定义全局 Hint

许多 Hint 既可以应用于特定的表或索引,也可以更全局地应用于视图中的表或一部分索引的列。语法元素 tablespecindexspec 定义了这些全局 Hint。

以下是 tablespec 的语法:

  1. [ view.[ view. ]... ]table

您必须完全按照在语句中显示的方式来指定要访问的表。如果该语句使用表的别名,则在 Hint 中使用也使用别名而不是表名。但是,即使 Schema 名称出现在语句中,也不要在 Hint 中使用的表名中包含 Schema 名称。

注意

使用 tablespec 子句指定全局 Hint 对于使用 ANSI 连接的查询不起作用,因为优化器在解析期间会生成额外的视图。相反,可以通过 @queryblock 来指定该提示所应用到的查询块。

以下是 indexspec 的语法:

  1. { index
  2. | ( [ table. ]column [ [ table. ]column ]...)
  3. }

在 Hint 的说明部分,当 tablespec 后跟着 indexspec 时,允许但不要求使用逗号来分隔表名和索引名。也允许(但不是必需)使用逗号分隔多次出现的 indexspec