首批通过分布式安全可靠测评,为关键业务系统打造
Hint 概述
更新时间:2026-06-09 10:24:57
Hint 是一种 SQL 语句注释,用于将指令传递给 OceanBase 数据库优化器。通过 Hint 可以使优化器生成指定的执行计划。
一般情况下,优化器会为用户查询选择最佳的执行计划,不需要用户使用 Hint 指定。当优化器生成的执行计划可能无法满足用户的要求时,需要用户使用 Hint 来主动指定并生成特殊的执行计划。
需要注意的是,在收集了相关表的统计信息并且在没有 Hint 的情况下使用 EXPLAIN PLAN 语句评估了优化器计划之后,才建议您谨慎考虑使用 Hint。更改数据库条件以及在后续版本中增强查询性能可能会导致您代码中的 Hint 对性能产生重大影响。
如何使用 Hint
Hint 的使用说明和注意事项
一条语句只能包含一个 Hint 注释,并且该注释必须跟随 CREATE、SELECT、UPDATE、INSERT、REPLACE 或 DELETE 关键字。Hint 只影响优化器所生成的执行计划的逻辑,而不影响 SQL 语句的语义。
- Hint 在语句注释中的语法格式如下:
{CREATE|DELETE|INSERT|SELECT|UPDATE|REPLACE} /*+ hint_text [,hint_text...] */
定义 Hint 时需要注意的一些规则:
Hint 从语法上看是一种特殊的 SQL 注释,注释以
/*+起始,且不允许有空格。如果服务器端无法识别 SQL 语句中的 Hint,那么优化器会选择忽略用户指定的 Hint 而使用默认计划所生成的执行逻辑。
每一个
SELECT等关键字后仅能添加一段 Hint,这一段 Hint 内部可以包含多个 Hint。Hint 注释起始/*+的+和 Hint 文本之间可以有空格,也可以不加空格。如果注释中包含多个 Hint,则 Hint 间至少用一个空格进行分隔。下方示例中,
/*+ hint1 */与/*+ hint3 hint4 */均为有效 Hint,/*+ hint2 */为无效 Hint。select /*+ hint1 */ /*+ hint2 */ * from t1, (select /*+ hint3 hint4 */ t2.* from t2, t3) v where t1.c1 = v.c1;对于存在多个可添加 Hint 位置的查询,在查询中可以使用多段 Hint。
Hint 包含拼写错误或语法错误时会被忽略。但是,数据库会考虑在同一注释中使用其他正确指定的 Hint。
不跟随
CREATE、DELETE、INSERT、REPLACE、SELECT或UPDATE关键字的 Hint 无效。Hint 的组合相互冲突时 Hint 无效。但是,数据库会在同一注释中考虑使用其他不冲突的 Hint。
由于 Hint 作为注释被添加到查询中,部分客户端/驱动可能会移除查询中注释,导致 Hint 失效。
在 Hint 中定义查询块
您可以通过在许多 Hint 中定义一个可选的查询块名称,以此来指定该 Hint 适用的查询块。更多信息,参见使用 Query Block Name 和 QB_NAME Hint 控制查询优化
使用此语法,允许您在外部查询中指定一个应用于嵌入式视图的 Hint。
查询块参数的语法格式为 @queryblock,其中 queryblock 是在查询中被指定的查询块的标识符。queryblock 标识符可以是系统生成的,也可以是用户自己指定的。当您在查询块中直接指定要应用的 Hint 时,将忽略 @queryblock。
系统生成的标识符可以通过对查询使用
EXPLAIN生成。可以使用 QB_NAME 来指定用户自定义的名称。
Hint 的分类与作用
OceanBase 数据库的 Hint 分为两个主要类型:全局 Hint(Global Hint)和查询块 Hint(Query Block Hint)。
查询块 Hint 进一步细分为 QB_NAME Hint、Transform Hint 和 Optimizer Hint,每种 Hint 根据其在优化器中的作用而有不同的分类。
全局 Hint(Global Hint)
全局 Hint 作用于整个查询,无论其在查询中的位置如何,都会产生相同的效果。例如,以下两个查询中使用的并行执行 Hint 是等价的:
select /*+ parallel(8) */ * from ( select * from t1);
select * from ( select /*+ parallel(8) */ * from t1);
全局 Hint 的定义
全局 Hint 可以针对特定的表或索引,也可以更广泛地应用于视图中的表或索引的一部分。使用 tablespec 和 indexspec 可以定义全局 Hint 的作用对象:
tablespec:定义全局 Hint 作用的表。在使用 Hint 时,需要严格按照查询语句中展现的表名称或别名。如果查询使用了表的别名,则 Hint 也应该使用相应的别名。[ view.[, view. ]... ] table_name注意:在查询中即使包含了 Schema 名称,也不应在 Hint 中包含 Schema 名称。
注意:对于使用 ANSI 连接的查询,使用
tablespec子句指定的全局 Hint 无效,这是因为优化器在解析过程中会生成额外的视图。在这种情况下,应通过@queryblock来指定查询块的 Hint。indexspec:定义全局 Hint 作用的索引。在说明 Hint 时,tablespec后可以跟随indexspec,使用逗号分隔表名和索引名是可选的。{ index | ( [ table. ] column_name [ [ table. ] column_name ]... ) }
查询块 Hint(Query Block Hint)
当 OceanBase 优化器解析查询时,会根据查询的结构将其分为多个查询块,每个查询块拥有自己的查询块名(Query Block Name)。查询块名可以由优化器自动生成,也可以通过 QB_NAME Hint 显式指定。更多关于 Query Block Name 与 QB_NAME Hint 的信息,例如使用查询块 Hint 指定 Hint 的作用范围或作用对象等,参见 Query Block Name 与 QB_NAME Hint。
例如,在以下查询中,外层查询块的名字是 qb1,内联视图 v 中的查询块的名字是 qb2:
select /*+ qb_name(qb1) */ * from ( select /*+ qb_name(qb2) */ * from t1 ) v;
查询块 Hint 只在特定的查询块内有效。指定查询块 Hint 生效的方式有两种:
- 直接将 Hint 添加到指定查询块中。
- 在 Hint 中指定查询块名,语法格式为
Hint_Name(@qb_name ...)。
例如,以下查询中,no_merge Hint 直接添加到查询块 qb2 中,并在该块内生效;index(@qb2 t1 idx) Hint 添加到查询块 qb1 中,并通过指定查询块名令其在查询块 qb2 内生效:
select /*+ index(@qb2 t1 idx) qb_name(qb1) */ *
from ( select /*+ no_merge qb_name(qb2) */ * from t1 ) v;
在查询块 Hint 中,除了 QB_NAME Hint 用于指定当前查询块的名字外,其它 Hint 分别在优化器的查询改写和计划生成阶段发挥作用:Transform Hint 干预查询改写行为,而 Optimizer Hint 干预计划生成行为。