---
title: "Optimizer Hint - OceanBase 数据库 V4.3.1 | OceanBase 文档中心"
description: Optimizer Hint Hint 机制可以使优化器生成指定的执行计划。 一般情况下，优化器会为用户查询选择最佳的执行计划，不需要用户使用 Hint 指定。但在某些场景下，优化器生成的执行计划可能不满足用户的要求，这时就需要用户使用 Hint 来指定生成某种执行计划。 Hint 语法 Hint 从语法上看是一种特…
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 4.3.1

# Optimizer Hint

更新时间：2026-04-10 11:58:01

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.3.1/zh-CN/700.reference/1000.performance-tuning-guide/500.sql-optimization/400.sql-optimization/700.manage-execution-plans/100.optimizer-hint.md)  

Hint 机制可以使优化器生成指定的执行计划。

一般情况下，优化器会为用户查询选择最佳的执行计划，不需要用户使用 Hint 指定。但在某些场景下，优化器生成的执行计划可能不满足用户的要求，这时就需要用户使用 Hint 来指定生成某种执行计划。

## Hint 语法

Hint 从语法上看是一种特殊的 SQL 注释，所不同的是在注释的左标记后（"/*"符号）增加了一个"+"。 既然是注释，如果服务器端无法识别 SQL 语句中的 Hint，优化器会选择忽略用户 Hint 而使用默认的计划生成逻辑结构。另外，Hint 只影响优化器生成计划的逻辑结构，而不影响 SQL 语句的语义。

```sql
{ DELETE | INSERT | SELECT | UPDATE | REPLACE } /*+ [hint_text][,hint_text]... */

```

#### 注意

如果使用 MySQL 的 C 客户端执行带 Hint 的 SQL 语句，需要使用 `-c` 选项登录，否则 MySQL 客户端会将 Hint 作为注释从用户 SQL 语句中去除，导致系统无法收到用户 Hint。

### Hint 参数

Hint 相关参数名称、语义和语法如下表所示。

| **名称** | **语法** | **语义** |
| --- | --- | --- |
| NO_REWRITE | NO_REWRITE | 禁止 SQL 改写。 |
| READ_CONSISTENCY | READ_CONSISTENCY (WEAK[STRONGFROZEN]) | 读一致性设置（弱/强）。 |
| INDEX_HINT | /*+ INDEX(table_name index_name) */ | 设置表索引。 |
| QUERY_TIMEOUT | QUERY_TIMEOUT(INTNUM) | 设置超时时间。 |
| LOG_LEVEL | LOG_LEVEL([']log_level[']) | 设置日志级别，当设置模块级别语句时候，以第一个单引号（'）作为开始，第二个单引号（'）作为结束；例如'DEBUG'。 |
| LEADING | LEADING([qb_name] TBL_NAME_LIST) | 设置联接顺序。 |
| ORDERED | ORDERED | 设置按照 SQL 中的顺序进行联接。 |
| FULL | FULL([qb_name] TBL_NAME) | 设置表访问路径为主表等价于 `INDEX(TBL_NAME PRIMARY)`。 |
| USE_PLAN_CACHE | USE_PLAN_CACHE(NONE[DEFAULT]) | 设置是否使用计划缓存：   - `NONE`：表示不使用计划缓存。 - `DEFAULT`：表示按照服务器本身的设置来决定是否使用计划缓存。 |
| USE_MERGE | USE_MERGE([qb_name] TBL_NAME_LIST) | 设置指定表在作为右表时使用 Merge Join。 |
| USE_HASH | USE_HASH([qb_name] TBL_NAME_LIST) | 设置指定表在作为右表时使用 Hash Join。 |
| NO_USE_HASH | NO_USE_HASH([qb_name] TBL_NAME_LIST) | 设置指定表在作为右表时不使用 Hash Join。 |
| USE_NL | USE_NL([qb_name] TBL_NAME_LIST) | 设置指定表在作为右表时使用 Nested Loop Join。 |
| USE_BNL | USE_BNL([qb_name] TBL_NAME_LIST) | 设置指定表在作为右表时使用 Block Nested Loop Join |
| USE_HASH_AGGREGATION | USE_HASH_AGGREGATION([qb_name]) | 设置聚合算法为 Hash。例如 Hash Group By 或者 Hash Distinct。 |
| NO_USE_HASH_AGGREGATION | NO_USE_HASH_AGGREGATION([qb_name]) | 设置 Aggregate 方法不使用 Hash Aggregate，使用 Merge Group By 或者 Merge Distinct。 |
| USE_LATE_MATERIALIZATION | USE_LATE_MATERIALIZATION | 设置使用晚期物化。 |
| NO_USE_LATE_MATERIALIZATION | NO_USE_LATE_MATERIALIZATION | 设置不使用晚期物化。 |
| TRACE_LOG | TRACE_LOG | 设置收集 Trace 记录用于 `SHOW TRACE` 展示。 |
| QB_NAME | QB_NAME( NAME ) | 设置 Query Block 的名称。 |
| PARALLEL | PARALLEL(INTNUM) | 设置分布式执行并行度。 |
| TOPK | TOPK(PRECISION MINIMUM_ROWS) | 设置模糊查询的精度和最小行数。 其中 `PRECSION` 为整型，取值范围[0，100]，表示模糊查询的行数百分比；`MINIMUM_ROWS` 为最小返回行数。 |
| MAX_CONCURRENT\|MAX_CONCURRENT(n) | 限制这个 SQL 文本的并发数。 |

#### 说明

- `QB_NAME` 语法是: `@NAME`
 - `TBL_NAME` 语法是: `[db_name.]relation_name [qb_name]`

## QB_NAME 参数

在 DML 语句中，每一个 `query_block` 都会有一个 `QB_NAME`（Query Block Name），可以由用户指定，也可以由系统自动生成。在用户没有用 Hint 指定 `QB_NAME` 的时候，系统会按照 `SEL$1`、`SEL$2`、`UPD$1`、`DEL$1` 方式从左到右（实际也是 Resolver 的解析顺序）依次生成。

通过 `QB_NAME` 可以精确定位到每一个表，也可以在某处指定任意 Query Block 的行为。`TBL_NAME` 中的 `QB_NAME` 用于定位表，在 Hint 中最前面的 `QB_NAME` 用于定位 Hint 作用于哪一个 `query_block`。

如下例所示，按照默认规则，会为 `SEL$1` 中的 `t1` 表选择 `t1_c1` 路径，为 `SEL$2` 中的 `t2` 表选择主表（Primary）访问。

```sql
obclient> CREATE TABLE t1(c1 INT, c2 INT, KEY t1_c1(c1));
Query OK, 0 rows affected

obclient> CREATE TABLE t2(c1 INT, c2 INT, KEY t2_c1(c1));
Query OK, 0 rows affected

obclient> EXPLAIN SELECT * FROM t1, (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5)
 WHERE t1.c1 = 1;
+-----------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                |
+-----------------------------------------------------------------------------------------------------------+
| ======================================================================                                    |
| |ID|OPERATOR                   |NAME           |EST.ROWS|EST.TIME(us)|                                    |
| ----------------------------------------------------------------------                                    |
| |0 |NESTED-LOOP JOIN CARTESIAN |               |1       |7           |                                    |
| |1 |├─TABLE RANGE SCAN         |t1(t1_c1)      |1       |7           |                                    |
| |2 |└─MATERIAL                 |               |1       |3           |                                    |
| |3 |  └─SUBPLAN SCAN           |ANONYMOUS_VIEW1|1       |3           |                                    |
| |4 |    └─TABLE FULL SCAN      |t2             |1       |3           |                                    |
| ======================================================================                                    |
| Outputs & filters:                                                                                        |
| -------------------------------------                                                                     |
|   0 - output([t1.c1], [t1.c2], [ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16        |
|       conds(nil), nl_params_(nil), use_batch=false                                                        |
|   1 - output([t1.c1], [t1.c2]), filter(nil), rowset=16                                                    |
|       access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0)                                       |
|       is_index_back=true, is_global_index=false,                                                          |
|       range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX),                                      |
|       range_cond([t1.c1 = 1])                                                                             |
|   2 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16                          |
|   3 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16                          |
|       access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2])                                                  |
|   4 - output([t2.c1], [t2.c2]), filter([t2.c2 = 1]), rowset=16                                            |
|       access([t2.c2], [t2.c1]), partitions(p0)                                                            |
|       limit(5), offset(nil), is_index_back=false, is_global_index=false, filter_before_indexback[false],  |
|       range_key([t2.__pk_increment]), range(MIN ; MAX)always true                                         |
+-----------------------------------------------------------------------------------------------------------+
25 rows in set

```

如果 SQL 通过 Hint 来指定 `SEL$1` 的 `t1` 表走主表，`SEL$2` 的 `t2` 表走索引，示例如下：

```sql
obclient> EXPLAIN SELECT /*+INDEX(t1 PRIMARY) INDEX(@SEL$2 t2 t2_c1)*/ *
        FROM t1 , (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5)
        WHERE t1.c1 = 1;
+----------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                               |
+----------------------------------------------------------------------------------------------------------+
| ======================================================================                                   |
| |ID|OPERATOR                   |NAME           |EST.ROWS|EST.TIME(us)|                                   |
| ----------------------------------------------------------------------                                   |
| |0 |NESTED-LOOP JOIN CARTESIAN |               |1       |3           |                                   |
| |1 |├─TABLE FULL SCAN          |t1             |1       |3           |                                   |
| |2 |└─MATERIAL                 |               |1       |7           |                                   |
| |3 |  └─SUBPLAN SCAN           |ANONYMOUS_VIEW1|1       |7           |                                   |
| |4 |    └─TABLE FULL SCAN      |t2(t2_c1)      |1       |7           |                                   |
| ======================================================================                                   |
| Outputs & filters:                                                                                       |
| -------------------------------------                                                                    |
|   0 - output([t1.c1], [t1.c2], [ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16       |
|       conds(nil), nl_params_(nil), use_batch=false                                                       |
|   1 - output([t1.c1], [t1.c2]), filter([t1.c1 = 1]), rowset=16                                           |
|       access([t1.c1], [t1.c2]), partitions(p0)                                                           |
|       is_index_back=false, is_global_index=false, filter_before_indexback[false],                        |
|       range_key([t1.__pk_increment]), range(MIN ; MAX)always true                                        |
|   2 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16                         |
|   3 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16                         |
|       access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2])                                                 |
|   4 - output([t2.c1], [t2.c2]), filter([t2.c2 = 1]), rowset=16                                           |
|       access([t2.__pk_increment], [t2.c2], [t2.c1]), partitions(p0)                                      |
|       limit(5), offset(nil), is_index_back=true, is_global_index=false, filter_before_indexback[false],  |
|       range_key([t2.c1], [t2.__pk_increment]), range(MIN,MIN ; MAX,MAX)always true                       |
+----------------------------------------------------------------------------------------------------------+
24 rows in set

```

#### 说明

由于 `INDEX(t1 PRIMARY)` 本来就存在于 `SEL$1`，可以不用再指定 Hint 作用的 Query Block。

上述示例中 SQL 也可以写成如下方式：

```sql
SELECT /*+INDEX(t1 PRIMARY) INDEX(@SEL$2 t2@SEL$2 t2_c1)*/ * FROM t1 , (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5) WHERE t1.c1 = 1;

```

或：

```sql
SELECT /*+INDEX(t1 PRIMARY)*/ * FROM t1 , (SELECT /*+INDEX(t2 t2_c1)*/ * FROM t2 WHERE c2 = 1 LIMIT 5) WHERE t1.c1 = 1;

```

或：

```sql
SELECT /*+INDEX(@SEL$1 t1 PRIMARY) INDEX(@SEL$2 t2 t2_c1)*/ * FROM t1 , (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5) WHERE t1.c1 = 1;

```

对于该 Hint，可以通过 `EXPLAIN EXTENDED` 命令的执行结果中的 `Outline Data` 来查看它的所有信息。

```sql
obclient> EXPLAIN EXTENDED SELECT * FROM t1, (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5)
 WHERE t1.c1 = 1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                         |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ======================================================================                                                                                             |
| |ID|OPERATOR                   |NAME           |EST.ROWS|EST.TIME(us)|                                                                                             |
| ----------------------------------------------------------------------                                                                                             |
| |0 |NESTED-LOOP JOIN CARTESIAN |               |1       |7           |                                                                                             |
| |1 |├─TABLE RANGE SCAN         |t1(t1_c1)      |1       |7           |                                                                                             |
| |2 |└─MATERIAL                 |               |1       |3           |                                                                                             |
| |3 |  └─SUBPLAN SCAN           |ANONYMOUS_VIEW1|1       |3           |                                                                                             |
| |4 |    └─TABLE FULL SCAN      |t2             |1       |3           |                                                                                             |
| ======================================================================                                                                                             |
| Outputs & filters:                                                                                                                                                 |
| -------------------------------------                                                                                                                              |
|   0 - output([t1.c1(0x7f20d7035330)], [t1.c2(0x7f20d70358b0)], [ANONYMOUS_VIEW1.c1(0x7f20d7035be0)], [ANONYMOUS_VIEW1.c2(0x7f20d7035f10)]), filter(nil), rowset=16 |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                                                 |
|   1 - output([t1.c1(0x7f20d7035330)], [t1.c2(0x7f20d70358b0)]), filter(nil), rowset=16                                                                             |
|       access([t1.__pk_increment(0x7f20d7036b10)], [t1.c1(0x7f20d7035330)], [t1.c2(0x7f20d70358b0)]), partitions(p0)                                                |
|       is_index_back=true, is_global_index=false,                                                                                                                   |
|       range_key([t1.c1(0x7f20d7035330)], [t1.__pk_increment(0x7f20d7036b10)]), range(1,MIN ; 1,MAX),                                                               |
|       range_cond([t1.c1(0x7f20d7035330) = 1(0x7f20d7034b70)])                                                                                                      |
|   2 - output([ANONYMOUS_VIEW1.c1(0x7f20d7035be0)], [ANONYMOUS_VIEW1.c2(0x7f20d7035f10)]), filter(nil), rowset=16                                                   |
|   3 - output([ANONYMOUS_VIEW1.c1(0x7f20d7035be0)], [ANONYMOUS_VIEW1.c2(0x7f20d7035f10)]), filter(nil), rowset=16                                                   |
|       access([ANONYMOUS_VIEW1.c1(0x7f20d7035be0)], [ANONYMOUS_VIEW1.c2(0x7f20d7035f10)])                                                                           |
|   4 - output([t2.c1(0x7f20d7033a10)], [t2.c2(0x7f20d7033490)]), filter([t2.c2(0x7f20d7033490) = 1(0x7f20d7032cd0)]), rowset=16                                     |
|       access([t2.c2(0x7f20d7033490)], [t2.c1(0x7f20d7033a10)]), partitions(p0)                                                                                     |
|       limit(5), offset(nil), is_index_back=false, is_global_index=false, filter_before_indexback[false],                                                           |
|       range_key([t2.__pk_increment(0x7f20d70365e0)]), range(MIN ; MAX)always true                                                                                  |
| Used Hint:                                                                                                                                                         |
| -------------------------------------                                                                                                                              |
|   /*+                                                                                                                                                              |
|                                                                                                                                                                    |
|   */                                                                                                                                                               |
| Qb name trace:                                                                                                                                                     |
| -------------------------------------                                                                                                                              |
|   stmt_id:0, stmt_type:T_EXPLAIN                                                                                                                                   |
|   stmt_id:1, SEL$1                                                                                                                                                 |
|   stmt_id:2, SEL$2                                                                                                                                                 |
| Outline Data:                                                                                                                                                      |
| -------------------------------------                                                                                                                              |
|   /*+                                                                                                                                                              |
|       BEGIN_OUTLINE_DATA                                                                                                                                           |
|       LEADING(@"SEL$1" ("aabb"."t1"@"SEL$1" "ANONYMOUS_VIEW1"@"SEL$1"))                                                                                            |
|       USE_NL(@"SEL$1" "ANONYMOUS_VIEW1"@"SEL$1")                                                                                                                   |
|       USE_NL_MATERIALIZATION(@"SEL$1" "ANONYMOUS_VIEW1"@"SEL$1")                                                                                                   |
|       INDEX(@"SEL$1" "aabb"."t1"@"SEL$1" "t1_c1")                                                                                                                  |
|       FULL(@"SEL$2" "aabb"."t2"@"SEL$2")                                                                                                                           |
|       OPTIMIZER_FEATURES_ENABLE('4.3.0.0')                                                                                                                         |
|       END_OUTLINE_DATA                                                                                                                                             |
|   */                                                                                                                                                               |
| Optimization Info:                                                                                                                                                 |
| -------------------------------------                                                                                                                              |
|   t1:                                                                                                                                                              |
|       table_rows:1                                                                                                                                                 |
|       physical_range_rows:1                                                                                                                                        |
|       logical_range_rows:1                                                                                                                                         |
|       index_back_rows:1                                                                                                                                            |
|       output_rows:1                                                                                                                                                |
|       table_dop:1                                                                                                                                                  |
|       dop_method:Table DOP                                                                                                                                         |
|       avaiable_index_name:[t1_c1, t1]                                                                                                                              |
|       unstable_index_name:[t1]                                                                                                                                     |
|       stats version:0                                                                                                                                              |
|       dynamic sampling level:0                                                                                                                                     |
|       estimation method:[DEFAULT, STORAGE]                                                                                                                         |
|   t2:                                                                                                                                                              |
|       table_rows:1                                                                                                                                                 |
|       physical_range_rows:1                                                                                                                                        |
|       logical_range_rows:1                                                                                                                                         |
|       index_back_rows:0                                                                                                                                            |
|       output_rows:1                                                                                                                                                |
|       table_dop:1                                                                                                                                                  |
|       dop_method:Table DOP                                                                                                                                         |
|       avaiable_index_name:[t2_c1, t2]                                                                                                                              |
|       pruned_index_name:[t2_c1]                                                                                                                                    |
|       stats version:0                                                                                                                                              |
|       dynamic sampling level:0                                                                                                                                     |
|       estimation method:[DEFAULT, STORAGE]                                                                                                                         |
|   Plan Type:                                                                                                                                                       |
|       LOCAL                                                                                                                                                        |
|   Note:                                                                                                                                                            |
|       Degree of Parallelisim is 1 because of table property                                                                                                        |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
79 rows in set

```

## Hint 使用规则

Hint 的一般使用规则如下：

- 对于没有指定 Query Block 的 Hint 表明作用于本 Query Block。

  **示例 1：由于`t2` 表在 Query Block2，并且无法通过改写提升到 Query Block1，所以 Hint 无法生效。**

  ```sql
  obclient> EXPLAIN SELECT /*+INDEX(t2 t2_c1)*/ *
          FROM t1 , (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5)
          WHERE t1.c1 = 1;
  +-----------------------------------------------------------------------------------------------------------+
  | Query Plan                                                                                                |
  +-----------------------------------------------------------------------------------------------------------+
  | ======================================================================                                    |
  | |ID|OPERATOR                   |NAME           |EST.ROWS|EST.TIME(us)|                                    |
  | ----------------------------------------------------------------------                                    |
  | |0 |NESTED-LOOP JOIN CARTESIAN |               |1       |7           |                                    |
  | |1 |├─TABLE RANGE SCAN         |t1(t1_c1)      |1       |7           |                                    |
  | |2 |└─MATERIAL                 |               |1       |3           |                                    |
  | |3 |  └─SUBPLAN SCAN           |ANONYMOUS_VIEW1|1       |3           |                                    |
  | |4 |    └─TABLE FULL SCAN      |t2             |1       |3           |                                    |
  | ======================================================================                                    |
  | Outputs & filters:                                                                                        |
  | -------------------------------------                                                                     |
  |   0 - output([t1.c1], [t1.c2], [ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16        |
  |       conds(nil), nl_params_(nil), use_batch=false                                                        |
  |   1 - output([t1.c1], [t1.c2]), filter(nil), rowset=16                                                    |
  |       access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0)                                       |
  |       is_index_back=true, is_global_index=false,                                                          |
  |       range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX),                                      |
  |       range_cond([t1.c1 = 1])                                                                             |
  |   2 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16                          |
  |   3 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16                          |
  |       access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2])                                                  |
  |   4 - output([t2.c1], [t2.c2]), filter([t2.c2 = 1]), rowset=16                                            |
  |       access([t2.c2], [t2.c1]), partitions(p0)                                                            |
  |       limit(5), offset(nil), is_index_back=false, is_global_index=false, filter_before_indexback[false],  |
  |       range_key([t2.__pk_increment]), range(MIN ; MAX)always true                                         |
  +-----------------------------------------------------------------------------------------------------------+
  25 rows in set

  ```

  **示例 2：如果优化器能够重新整合子查询与外层查询，从而只使用一个 Query Block，那么 Hint 可能生效。**

  ```sql
  obclient> EXPLAIN SELECT /*+INDEX(t2 t2_c1)*/ *
          FROM t1 , (SELECT * FROM t2 WHERE c2 = 1)
          WHERE t1.c1 = 1;
  +------------------------------------------------------------------------------------+
  | Query Plan                                                                         |
  +------------------------------------------------------------------------------------+
  | ================================================================                   |
  | |ID|OPERATOR                   |NAME     |EST.ROWS|EST.TIME(us)|                   |
  | ----------------------------------------------------------------                   |
  | |0 |NESTED-LOOP JOIN CARTESIAN |         |1       |7           |                   |
  | |1 |├─TABLE RANGE SCAN         |t1(t1_c1)|1       |7           |                   |
  | |2 |└─MATERIAL                 |         |1       |7           |                   |
  | |3 |  └─TABLE FULL SCAN        |t2(t2_c1)|1       |7           |                   |
  | ================================================================                   |
  | Outputs & filters:                                                                 |
  | -------------------------------------                                              |
  |   0 - output([t1.c1], [t1.c2], [t2.c1], [t2.c2]), filter(nil), rowset=16           |
  |       conds(nil), nl_params_(nil), use_batch=false                                 |
  |   1 - output([t1.c1], [t1.c2]), filter(nil), rowset=16                             |
  |       access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0)                |
  |       is_index_back=true, is_global_index=false,                                   |
  |       range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX),               |
  |       range_cond([t1.c1 = 1])                                                      |
  |   2 - output([t2.c1], [t2.c2]), filter(nil), rowset=16                             |
  |   3 - output([t2.c2], [t2.c1]), filter([t2.c2 = 1]), rowset=16                     |
  |       access([t2.__pk_increment], [t2.c2], [t2.c1]), partitions(p0)                |
  |       is_index_back=true, is_global_index=false, filter_before_indexback[false],   |
  |       range_key([t2.c1], [t2.__pk_increment]), range(MIN,MIN ; MAX,MAX)always true |
  +------------------------------------------------------------------------------------+
  22 rows in set

  ```

对于上面的示例，如果优化器由于某些原因（比如子查询内部操作阻止了提升合并）无法将子查询 (`SELECT * FROM t2 WHERE c2 = 1`) 合并到外层查询，那么 t2 表仍然被视为子查询的一部分，因此外层查询中的 Hint 无效。

如下示例，由于外层查询和子查询均引用了同一张表 t1，并且都试图利用 PRIMARY 索引，这可能会导致优化器在解释和处理 Hint 时遇到冲突，从而使得 Hint 可能无效。

```sql
obclient> EXPLAIN SELECT /*+INDEX(t1 PRIMARY)*/ *
          FROM t1 , (SELECT * FROM t1 WHERE c1 = 1)
          WHERE t1.c1 = 1;
+--------------------------------------------------------------------------+
| Query Plan                                                               |
+--------------------------------------------------------------------------+
| ================================================================         |
| |ID|OPERATOR                   |NAME     |EST.ROWS|EST.TIME(us)|         |
| ----------------------------------------------------------------         |
| |0 |NESTED-LOOP JOIN CARTESIAN |         |1       |7           |         |
| |1 |├─TABLE RANGE SCAN         |t1(t1_c1)|1       |7           |         |
| |2 |└─MATERIAL                 |         |1       |7           |         |
| |3 |  └─TABLE RANGE SCAN       |t1(t1_c1)|1       |7           |         |
| ================================================================         |
| Outputs & filters:                                                       |
| -------------------------------------                                    |
|   0 - output([t1.c1], [t1.c2], [t1.c1], [t1.c2]), filter(nil), rowset=16 |
|       conds(nil), nl_params_(nil), use_batch=false                       |
|   1 - output([t1.c1], [t1.c2]), filter(nil), rowset=16                   |
|       access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0)      |
|       is_index_back=true, is_global_index=false,                         |
|       range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX),     |
|       range_cond([t1.c1 = 1])                                            |
|   2 - output([t1.c1], [t1.c2]), filter(nil), rowset=16                   |
|   3 - output([t1.c1], [t1.c2]), filter(nil), rowset=16                   |
|       access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0)      |
|       is_index_back=true, is_global_index=false,                         |
|       range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX),     |
|       range_cond([t1.c1 = 1])                                            |
+--------------------------------------------------------------------------+
23 rows in set

```

- 联接方法的 Hint 中指定的表如果找不到，则忽略该表，其他的指定依然生效；如果优化器不能生成指定的联接方法，就会选择其他方法，Hint 无效。
 - 联接顺序的 Hint 中如果存在表无法找到的情况，则该 Hint 完全失效。

## 常用 Hint 及语法

与其他数据库的行为相比，OceanBase 数据库优化器是动态规划的，已经考虑了所有可能的最优路径，Hint 主要作用是指定优化器的行为，并按照 Hint 执行 SQL 查询。

### INDEX Hint

`INDEX` Hint 的语法同时支持 MySQL 模式和 Oracle 模式。

- `INDEX` Hint 的 Oracle 语法如下：

```sql
SELECT/*+INDEX(table_name index_name) */ * FROM table_name;

```

- `INDEX` Hint 的 MySQL 语法如下：

```sql
table_name [[AS] alias] [index_hint_list]

index_hint_list:
index_hint [, index_hint] ...

index_hint:
USE {INDEX|KEY}
  [FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
  | IGNORE {INDEX|KEY}
  [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
  | FORCE {INDEX|KEY}
  [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)

index_list:
index_name [, index_name] ...

```

Oracle 模式的语法中一个表只能指定一个 `INDEX`，而 MySQL 模式的语法可以指定多个。但是 OceanBase 数据库中 MySQL 模式的语法虽然支持指定多个 `INDEX`，但是对于 `USE` 和 `FORCE` 方式，只会用第一个 `INDEX` 生成 `PATH`，即使 SQL 语句中没有该 `INDEX` 的 `filter` 而导致全部扫描同时回表（即 OceanBase 数据库当前设计是认为写 Hint 的人比程序更明白那条路径是更好的）。`IGNORE` 类型会忽略所有指定的 `INDEX`。`USE`、`FORCE` 方式和 Oracle 的Hint 方式实际是一样的，如果该方式的 `INDEX` 不存在或者处于 `invalid` 状态，则 Hint 无效。对于 `IGNORE` 方式，如果将包括主表在内的所有 `INDEX` 忽略，则 Hint 无效。

在 SQL 语句中，表名存在别名即 `table_name [AS] alias`，必须写表别名，才能使 `INDEX` 生效。示例如下：

```sql
obclient> create table t1(c1 int, c2 int, c3 int);
Query OK, 0 rows affected

obclient> create index idx1 on t1(c1);
Query OK, 0 rows affected

obclient> create index idx2 on t1(c2);
Query OK, 0 rows affected

obclient> insert into t1 with recursive cte(n) as (select 1 from dual union all select n+1 from cte where n < 1000) select n, mod(n, 3), n from cte;
Query OK, 1 row affected

obclient> analyze table t1 COMPUTE STATISTICS for all columns size 128;
Query OK, 0 rows affected

obclient> explain select * from t1 where c1 = 1 and c2 = 1;
+-----------------------------------------------------------------------------------+
| Query Plan                                                                        |
+-----------------------------------------------------------------------------------+
| ====================================================                              |
| |ID|OPERATOR        |NAME    |EST.ROWS|EST.TIME(us)|                              |
| ----------------------------------------------------                              |
| |0 |TABLE RANGE SCAN|t1(idx1)|1       |7           |                              |
| ====================================================                              |
| Outputs & filters:                                                                |
| -------------------------------------                                             |
|   0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c2 = 1]), rowset=16           |
|       access([t1.__pk_increment], [t1.c1], [t1.c2], [t1.c3]), partitions(p0)      |
|       is_index_back=true, is_global_index=false, filter_before_indexback[false],  |
|       range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX),              |
|       range_cond([t1.c1 = 1])                                                     |
+-----------------------------------------------------------------------------------+
12 rows in set

-------生效的 index
obclient> explain select /*+index(t idx2)*/ * from t1 t where c1 = 1 and c2 = 1;
+-----------------------------------------------------------------------------------+
| Query Plan                                                                        |
+-----------------------------------------------------------------------------------+
| ===================================================                               |
| |ID|OPERATOR        |NAME   |EST.ROWS|EST.TIME(us)|                               |
| ---------------------------------------------------                               |
| |0 |TABLE RANGE SCAN|t(idx2)|1       |812         |                               |
| ===================================================                               |
| Outputs & filters:                                                                |
| -------------------------------------                                             |
|   0 - output([t.c1], [t.c2], [t.c3]), filter([t.c1 = 1]), rowset=16               |
|       access([t.__pk_increment], [t.c1], [t.c2], [t.c3]), partitions(p0)          |
|       is_index_back=true, is_global_index=false, filter_before_indexback[false],  |
|       range_key([t.c2], [t.__pk_increment]), range(1,MIN ; 1,MAX),                |
|       range_cond([t.c2 = 1])                                                      |
+-----------------------------------------------------------------------------------+
12 rows in set

-------不生效的 index
obclient> explain select /*+index(t1 idx2)*/ * from t1 t where c1 = 1 and c2 = 1;
+-----------------------------------------------------------------------------------+
| Query Plan                                                                        |
+-----------------------------------------------------------------------------------+
| ===================================================                               |
| |ID|OPERATOR        |NAME   |EST.ROWS|EST.TIME(us)|                               |
| ---------------------------------------------------                               |
| |0 |TABLE RANGE SCAN|t(idx1)|1       |7           |                               |
| ===================================================                               |
| Outputs & filters:                                                                |
| -------------------------------------                                             |
|   0 - output([t.c1], [t.c2], [t.c3]), filter([t.c2 = 1]), rowset=16               |
|       access([t.__pk_increment], [t.c1], [t.c2], [t.c3]), partitions(p0)          |
|       is_index_back=true, is_global_index=false, filter_before_indexback[false],  |
|       range_key([t.c1], [t.__pk_increment]), range(1,MIN ; 1,MAX),                |
|       range_cond([t.c1 = 1])                                                      |
+-----------------------------------------------------------------------------------+
12 rows in set

```

根据示例结果，`c1 = 1` 过滤性优于 `c2 = 1`，INDEX Hint 不生效时使用优化器索引选择机制使用了 `IDX1`。

### FULL Hint

`FULL` Hint 的语法是用于指定表使用主表扫描，语法如下：

```sql
/*+ FULL(table_name)*/

```

`FULL` Hint 用于为指定表选择主表扫描，等价于 `INDEX` Hint `/*+ INDEX(table_name PRIMARY)*/`。

### ORDERED Hint

`ORDERED` Hint 可以指定按照 `FROM` 后面的表顺序作为联接顺序，语法如下：

```sql
 /*+ ORDERED */

```

如果指定该 Hint 后发生 SQL 改写，那么就按照改写后的 `stmt` 中 From Items 的顺序联接，因为改写时候 `sub_query` 会在 From Items 中对应位置填放新的 Table Item。

### LEADING Hint

`LEADING` Hint 可以指定表的联接顺序，语法如下：

```sql
 /*+ LEADING(table_name_list)*/

```

在 `table_name_list` 中可以使用 `()` 表示内部各表的联接优先级，指定复杂联接。示例如下：

```sql
obclient> EXPLAIN BASIC SELECT /*+LEADING(d c b a)*/ * FROM t1 a, t1 b, t1 c, t1 d;
+---------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                            |
+---------------------------------------------------------------------------------------------------------------------------------------+
| =========================================                                                                                             |
| |ID|OPERATOR                       |NAME|                                                                                             |
| -----------------------------------------                                                                                             |
| |0 |NESTED-LOOP JOIN CARTESIAN     |    |                                                                                             |
| |1 |├─NESTED-LOOP JOIN CARTESIAN   |    |                                                                                             |
| |2 |│ ├─NESTED-LOOP JOIN CARTESIAN |    |                                                                                             |
| |3 |│ │ ├─TABLE FULL SCAN          |d   |                                                                                             |
| |4 |│ │ └─MATERIAL                 |    |                                                                                             |
| |5 |│ │   └─TABLE FULL SCAN        |c   |                                                                                             |
| |6 |│ └─MATERIAL                   |    |                                                                                             |
| |7 |│   └─TABLE FULL SCAN          |b   |                                                                                             |
| |8 |└─MATERIAL                     |    |                                                                                             |
| |9 |  └─TABLE FULL SCAN            |a   |                                                                                             |
| =========================================                                                                                             |
| Outputs & filters:                                                                                                                    |
| -------------------------------------                                                                                                 |
|   0 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   1 - output([b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256                         |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   2 - output([c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256                                                 |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   3 - output([d.c1], [d.c2], [d.c3]), filter(nil), rowset=256                                                                         |
|       access([d.c1], [d.c2], [d.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([d.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   4 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256                                                                         |
|   5 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256                                                                         |
|       access([c.c1], [c.c2], [c.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([c.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   6 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256                                                                         |
|   7 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256                                                                         |
|       access([b.c1], [b.c2], [b.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([b.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   8 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256                                                                         |
|   9 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256                                                                         |
|       access([a.c1], [a.c2], [a.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([a.__pk_increment]), range(MIN ; MAX)always true                                                                      |
+---------------------------------------------------------------------------------------------------------------------------------------+
41 rows in set

obclient> EXPLAIN BASIC SELECT /*+LEADING((d c) (b a))*/ * FROM  t1 a, t1 b, t1 c, t1 d;
+---------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                            |
+---------------------------------------------------------------------------------------------------------------------------------------+
| =========================================                                                                                             |
| |ID|OPERATOR                       |NAME|                                                                                             |
| -----------------------------------------                                                                                             |
| |0 |NESTED-LOOP JOIN CARTESIAN     |    |                                                                                             |
| |1 |├─NESTED-LOOP JOIN CARTESIAN   |    |                                                                                             |
| |2 |│ ├─TABLE FULL SCAN            |d   |                                                                                             |
| |3 |│ └─MATERIAL                   |    |                                                                                             |
| |4 |│   └─TABLE FULL SCAN          |c   |                                                                                             |
| |5 |└─MATERIAL                     |    |                                                                                             |
| |6 |  └─NESTED-LOOP JOIN CARTESIAN |    |                                                                                             |
| |7 |    ├─TABLE FULL SCAN          |b   |                                                                                             |
| |8 |    └─MATERIAL                 |    |                                                                                             |
| |9 |      └─TABLE FULL SCAN        |a   |                                                                                             |
| =========================================                                                                                             |
| Outputs & filters:                                                                                                                    |
| -------------------------------------                                                                                                 |
|   0 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   1 - output([c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256                                                 |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   2 - output([d.c1], [d.c2], [d.c3]), filter(nil), rowset=256                                                                         |
|       access([d.c1], [d.c2], [d.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([d.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   3 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256                                                                         |
|   4 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256                                                                         |
|       access([c.c1], [c.c2], [c.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([c.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   5 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3]), filter(nil), rowset=256                                                 |
|   6 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3]), filter(nil), rowset=256                                                 |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   7 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256                                                                         |
|       access([b.c1], [b.c2], [b.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([b.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   8 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256                                                                         |
|   9 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256                                                                         |
|       access([a.c1], [a.c2], [a.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([a.__pk_increment]), range(MIN ; MAX)always true                                                                      |
+---------------------------------------------------------------------------------------------------------------------------------------+
41 rows in set

obclient> EXPLAIN BASIC SELECT /*+LEADING((d c b) a))*/ * FROM t1 a, t1 b, t1 c, t1 d;
+---------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                            |
+---------------------------------------------------------------------------------------------------------------------------------------+
| =========================================                                                                                             |
| |ID|OPERATOR                       |NAME|                                                                                             |
| -----------------------------------------                                                                                             |
| |0 |NESTED-LOOP JOIN CARTESIAN     |    |                                                                                             |
| |1 |├─NESTED-LOOP JOIN CARTESIAN   |    |                                                                                             |
| |2 |│ ├─NESTED-LOOP JOIN CARTESIAN |    |                                                                                             |
| |3 |│ │ ├─TABLE FULL SCAN          |d   |                                                                                             |
| |4 |│ │ └─MATERIAL                 |    |                                                                                             |
| |5 |│ │   └─TABLE FULL SCAN        |c   |                                                                                             |
| |6 |│ └─MATERIAL                   |    |                                                                                             |
| |7 |│   └─TABLE FULL SCAN          |b   |                                                                                             |
| |8 |└─MATERIAL                     |    |                                                                                             |
| |9 |  └─TABLE FULL SCAN            |a   |                                                                                             |
| =========================================                                                                                             |
| Outputs & filters:                                                                                                                    |
| -------------------------------------                                                                                                 |
|   0 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   1 - output([b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256                         |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   2 - output([c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256                                                 |
|       conds(nil), nl_params_(nil), use_batch=false                                                                                    |
|   3 - output([d.c1], [d.c2], [d.c3]), filter(nil), rowset=256                                                                         |
|       access([d.c1], [d.c2], [d.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([d.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   4 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256                                                                         |
|   5 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256                                                                         |
|       access([c.c1], [c.c2], [c.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([c.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   6 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256                                                                         |
|   7 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256                                                                         |
|       access([b.c1], [b.c2], [b.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([b.__pk_increment]), range(MIN ; MAX)always true                                                                      |
|   8 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256                                                                         |
|   9 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256                                                                         |
|       access([a.c1], [a.c2], [a.c3]), partitions(p0)                                                                                  |
|       is_index_back=false, is_global_index=false,                                                                                     |
|       range_key([a.__pk_increment]), range(MIN ; MAX)always true                                                                      |
+---------------------------------------------------------------------------------------------------------------------------------------+
41 rows in set

```

为确保按照用户指定的顺序进行联接，`LEADING` Hint 的检查比较严格，如果发现 Hint 指定的 `table_name` 不存在，`LEADING` Hint 失效；如果发现 Hint 中存在重复表，`LEADING` Hint 失效。如果在 Optimizer 联接期间，按 `table_id` 无法在 From Items 中找到对应的表，则可能发生改写，那么该表及后面的表指定的 `JOIN` 顺序失效，该表前面的 `JOIN` 顺序依然有效。

### USE_MERGE Hint

`USE_MERGE` 可以指定表在联接时候使用 Merge Join 算法，将所指定的表作为右表。语法如下：

```sql
 /*+ USE_MERGE(table_name_list) */

```

#### 注意

OceanBase 数据库中 Merge Join 必须有等值条件的 `join-condition`，因此无等值条件的两个表联接，`use_merge` 会无效。

关于 Merge Join 算法是否认为 A Merge Join B 等效于 B Merge Join A，当前并没有最后结论。按照代价模型，Merge Join 计算代价时是区分左右表的，这也增加了 Hint 的灵活性，所以当前 Merge Join 区分左右表，即 `use_merge` 仅对表作为右表的时候生效。

### USE_NL Hint

和 join 相关的 Hint 的基本结构如下： `join_hint_name ( @ qb_name table_name_list)` 基本语义为，当联接的右表匹配 table_name_list 时，按照 Hint 语义生成计划。一般需要使用 `LEADING` Hint 指定联接顺序，使 table_name_list 中的表为右表，否则 Hint 会随着联接顺序变化而失效。

其中 table_name_list 可有以下形式：

- 单表 use_nl ( t1 ): 以 t1 为右表时使用 Nested Loop Join。
 - 多个单表 use_nl ( t1 t2 ... ): 以 t1 或 t2 等为右表时使用 Nested Loop Join。
 - 多表 use_nl ( (t1 t2) ): 以 t1 join t2 为右表时使用 Nested Loop Join，忽略 t1/t2 连接顺序和方法。
 - 多组表 use_nl ( t1 (t2 t3) (t4 t5 t6) ... ): 以 t1 / t2 join t3 / t4 join t5 join t6 等表为右表时使用 Nested Loop Join。

`USE_NL` 指定表作为右表，在联接的时候使用 Nested Loop Join 算法，语法如下：

```sql
/*+ USE_NL(table_name_list) */

```

示例如下：

```sql
obclient> CREATE TABLE t0(c1 INT, c2 INT, c3 INT);
obclient> CREATE TABLE t1(c1 INT, c2 INT, c3 INT);
obclient> CREATE TABLE t2(c1 INT, c2 INT, c3 INT);

obclient> EXPLAIN EXTENDED SELECT /*+LEADING(t0 t1) USE_NL(t1)*/ *
FROM t0, t1 WHERE t0.c1 = t1.c1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                                                 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ===================================================                                                                                                                                        |
| |ID|OPERATOR           |NAME|EST.ROWS|EST.TIME(us)|                                                                                                                                        |
| ---------------------------------------------------                                                                                                                                        |
| |0 |NESTED-LOOP JOIN   |    |1       |3           |                                                                                                                                        |
| |1 |├─TABLE FULL SCAN  |t0  |1       |3           |                                                                                                                                        |
| |2 |└─MATERIAL         |    |1       |3           |                                                                                                                                        |
| |3 |  └─TABLE FULL SCAN|t1  |1       |3           |                                                                                                                                        |
| ===================================================                                                                                                                                        |
| Outputs & filters:                                                                                                                                                                         |
| -------------------------------------                                                                                                                                                      |
|   0 - output([t0.c1(0x7f218dc21640)], [t0.c2(0x7f218dc21f00)], [t0.c3(0x7f218dc22230)], [t1.c1(0x7f218dc21980)], [t1.c2(0x7f218dc22560)], [t1.c3(0x7f218dc22890)]), filter(nil), rowset=16 |
|       conds([t0.c1(0x7f218dc21640) = t1.c1(0x7f218dc21980)(0x7f218dc20e80)]), nl_params_(nil), use_batch=false                                                                             |
|   1 - output([t0.c1(0x7f218dc21640)], [t0.c2(0x7f218dc21f00)], [t0.c3(0x7f218dc22230)]), filter(nil), rowset=16                                                                            |
|       access([t0.c1(0x7f218dc21640)], [t0.c2(0x7f218dc21f00)], [t0.c3(0x7f218dc22230)]), partitions(p0)                                                                                    |
|       is_index_back=false, is_global_index=false,                                                                                                                                          |
|       range_key([t0.__pk_increment(0x7f218dc230f0)]), range(MIN ; MAX)always true                                                                                                          |
|   2 - output([t1.c1(0x7f218dc21980)], [t1.c2(0x7f218dc22560)], [t1.c3(0x7f218dc22890)]), filter(nil), rowset=16                                                                            |
|   3 - output([t1.c1(0x7f218dc21980)], [t1.c2(0x7f218dc22560)], [t1.c3(0x7f218dc22890)]), filter(nil), rowset=16                                                                            |
|       access([t1.c1(0x7f218dc21980)], [t1.c2(0x7f218dc22560)], [t1.c3(0x7f218dc22890)]), partitions(p0)                                                                                    |
|       is_index_back=false, is_global_index=false,                                                                                                                                          |
|       range_key([t1.__pk_increment(0x7f218dc23420)]), range(MIN ; MAX)always true                                                                                                          |
| Used Hint:                                                                                                                                                                                 |
| -------------------------------------                                                                                                                                                      |
|   /*+                                                                                                                                                                                      |
|                                                                                                                                                                                            |
|       LEADING(("t0" "t1"))                                                                                                                                                                 |
|       USE_NL("t1")                                                                                                                                                                         |
|   */                                                                                                                                                                                       |
| Qb name trace:                                                                                                                                                                             |
| -------------------------------------                                                                                                                                                      |
|   stmt_id:0, stmt_type:T_EXPLAIN                                                                                                                                                           |
|   stmt_id:1, SEL$1                                                                                                                                                                         |
| Outline Data:                                                                                                                                                                              |
| -------------------------------------                                                                                                                                                      |
|   /*+                                                                                                                                                                                      |
|       BEGIN_OUTLINE_DATA                                                                                                                                                                   |
|       LEADING(@"SEL$1" ("cccc"."t0"@"SEL$1" "cccc"."t1"@"SEL$1"))                                                                                                                          |
|       USE_NL(@"SEL$1" "cccc"."t1"@"SEL$1")                                                                                                                                                 |
|       USE_NL_MATERIALIZATION(@"SEL$1" "cccc"."t1"@"SEL$1")                                                                                                                                 |
|       FULL(@"SEL$1" "cccc"."t0"@"SEL$1")                                                                                                                                                   |
|       FULL(@"SEL$1" "cccc"."t1"@"SEL$1")                                                                                                                                                   |
|       OPTIMIZER_FEATURES_ENABLE('4.3.0.0')                                                                                                                                                 |
|       END_OUTLINE_DATA                                                                                                                                                                     |
|   */                                                                                                                                                                                       |
| Optimization Info:                                                                                                                                                                         |
| -------------------------------------                                                                                                                                                      |
|   t0:                                                                                                                                                                                      |
|       table_rows:1                                                                                                                                                                         |
|       physical_range_rows:1                                                                                                                                                                |
|       logical_range_rows:1                                                                                                                                                                 |
|       index_back_rows:0                                                                                                                                                                    |
|       output_rows:1                                                                                                                                                                        |
|       table_dop:1                                                                                                                                                                          |
|       dop_method:Table DOP                                                                                                                                                                 |
|       avaiable_index_name:[t0]                                                                                                                                                             |
|       stats version:0                                                                                                                                                                      |
|       dynamic sampling level:1                                                                                                                                                             |
|       estimation method:[DYNAMIC SAMPLING FULL]                                                                                                                                            |
|   t1:                                                                                                                                                                                      |
|       table_rows:1                                                                                                                                                                         |
|       physical_range_rows:1                                                                                                                                                                |
|       logical_range_rows:1                                                                                                                                                                 |
|       index_back_rows:0                                                                                                                                                                    |
|       output_rows:1                                                                                                                                                                        |
|       table_dop:1                                                                                                                                                                          |
|       dop_method:Table DOP                                                                                                                                                                 |
|       avaiable_index_name:[t1]                                                                                                                                                             |
|       stats version:0                                                                                                                                                                      |
|       dynamic sampling level:1                                                                                                                                                             |
|       estimation method:[DYNAMIC SAMPLING FULL]                                                                                                                                            |
|   Plan Type:                                                                                                                                                                               |
|       LOCAL                                                                                                                                                                                |
|   Note:                                                                                                                                                                                    |
|       Degree of Parallelisim is 1 because of table property                                                                                                                                |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
74 rows in set

obclient> EXPLAIN EXTENDED SELECT /*+LEADING(t0 (t1 t2)) USE_NL((t1 t2))*/ *
FROM t0, t1, t2 WHERE t0.c1 = t1.c1 AND t0.c1 = t2.c1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                                                 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| =====================================================                                                                                                                                      |
| |ID|OPERATOR             |NAME|EST.ROWS|EST.TIME(us)|                                                                                                                                      |
| -----------------------------------------------------                                                                                                                                      |
| |0 |NESTED-LOOP JOIN     |    |1       |3           |                                                                                                                                      |
| |1 |├─TABLE FULL SCAN    |t0  |1       |3           |                                                                                                                                      |
| |2 |└─MATERIAL           |    |1       |5           |                                                                                                                                      |
| |3 |  └─HASH JOIN        |    |1       |5           |                                                                                                                                      |
| |4 |    ├─TABLE FULL SCAN|t1  |1       |3           |                                                                                                                                      |
| |5 |    └─TABLE FULL SCAN|t2  |1       |3           |                                                                                                                                      |
| =====================================================                                                                                                                                      |
| Outputs & filters:                                                                                                                                                                         |
| -------------------------------------                                                                                                                                                      |
|   0 - output([t0.c1(0x7f217d422a30)], [t0.c2(0x7f217d424700)], [t0.c3(0x7f217d424a30)], [t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)],                         |
|        [t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), filter(nil), rowset=16                                                                                  |
|       conds([t0.c1(0x7f217d422a30) = t1.c1(0x7f217d422d70)(0x7f217d422270)]), nl_params_(nil), use_batch=false                                                                             |
|   1 - output([t0.c1(0x7f217d422a30)], [t0.c2(0x7f217d424700)], [t0.c3(0x7f217d424a30)]), filter(nil), rowset=16                                                                            |
|       access([t0.c1(0x7f217d422a30)], [t0.c2(0x7f217d424700)], [t0.c3(0x7f217d424a30)]), partitions(p0)                                                                                    |
|       is_index_back=false, is_global_index=false,                                                                                                                                          |
|       range_key([t0.__pk_increment(0x7f217d426110)]), range(MIN ; MAX)always true                                                                                                          |
|   2 - output([t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)], [t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), filter(nil), rowset=16 |
|   3 - output([t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)], [t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), filter(nil), rowset=16 |
|       equal_conds([t1.c1(0x7f217d422d70) = t2.c1(0x7f217d424180)(0x7f217d4c2500)]), other_conds(nil)                                                                                       |
|   4 - output([t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)]), filter(nil), rowset=16                                                                            |
|       access([t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)]), partitions(p0)                                                                                    |
|       is_index_back=false, is_global_index=false,                                                                                                                                          |
|       range_key([t1.__pk_increment(0x7f217d426440)]), range(MIN ; MAX)always true                                                                                                          |
|   5 - output([t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), filter(nil), rowset=16                                                                            |
|       access([t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), partitions(p0)                                                                                    |
|       is_index_back=false, is_global_index=false,                                                                                                                                          |
|       range_key([t2.__pk_increment(0x7f217d426770)]), range(MIN ; MAX)always true                                                                                                          |
| Used Hint:                                                                                                                                                                                 |
| -------------------------------------                                                                                                                                                      |
|   /*+                                                                                                                                                                                      |
|                                                                                                                                                                                            |
|       LEADING(("t0" ("t1" "t2")))                                                                                                                                                          |
|       USE_NL(("t1" "t2"))                                                                                                                                                                  |
|   */                                                                                                                                                                                       |
| Qb name trace:                                                                                                                                                                             |
| -------------------------------------                                                                                                                                                      |
|   stmt_id:0, stmt_type:T_EXPLAIN                                                                                                                                                           |
|   stmt_id:1, SEL$1                                                                                                                                                                         |
| Outline Data:                                                                                                                                                                              |
| -------------------------------------                                                                                                                                                      |
|   /*+                                                                                                                                                                                      |
|       BEGIN_OUTLINE_DATA                                                                                                                                                                   |
|       LEADING(@"SEL$1" ("cccc"."t0"@"SEL$1" ("cccc"."t1"@"SEL$1" "cccc"."t2"@"SEL$1")))                                                                                                    |
|       USE_NL(@"SEL$1" ("cccc"."t2"@"SEL$1" "cccc"."t1"@"SEL$1"))                                                                                                                           |
|       USE_NL_MATERIALIZATION(@"SEL$1" ("cccc"."t2"@"SEL$1" "cccc"."t1"@"SEL$1"))                                                                                                           |
|       FULL(@"SEL$1" "cccc"."t0"@"SEL$1")                                                                                                                                                   |
|       USE_HASH(@"SEL$1" "cccc"."t2"@"SEL$1")                                                                                                                                               |
|       FULL(@"SEL$1" "cccc"."t1"@"SEL$1")                                                                                                                                                   |
|       FULL(@"SEL$1" "cccc"."t2"@"SEL$1")                                                                                                                                                   |
|       OPTIMIZER_FEATURES_ENABLE('4.3.0.0')                                                                                                                                                 |
|       END_OUTLINE_DATA                                                                                                                                                                     |
|   */                                                                                                                                                                                       |
| Optimization Info:                                                                                                                                                                         |
| -------------------------------------                                                                                                                                                      |
|   t0:                                                                                                                                                                                      |
|       table_rows:1                                                                                                                                                                         |
|       physical_range_rows:1                                                                                                                                                                |
|       logical_range_rows:1                                                                                                                                                                 |
|       index_back_rows:0                                                                                                                                                                    |
|       output_rows:1                                                                                                                                                                        |
|       table_dop:1                                                                                                                                                                          |
|       dop_method:Table DOP                                                                                                                                                                 |
|       avaiable_index_name:[t0]                                                                                                                                                             |
|       stats version:0                                                                                                                                                                      |
|       dynamic sampling level:1                                                                                                                                                             |
|       estimation method:[DYNAMIC SAMPLING FULL]                                                                                                                                            |
|   t1:                                                                                                                                                                                      |
|       table_rows:1                                                                                                                                                                         |
|       physical_range_rows:1                                                                                                                                                                |
|       logical_range_rows:1                                                                                                                                                                 |
|       index_back_rows:0                                                                                                                                                                    |
|       output_rows:1                                                                                                                                                                        |
|       table_dop:1                                                                                                                                                                          |
|       dop_method:Table DOP                                                                                                                                                                 |
|       avaiable_index_name:[t1]                                                                                                                                                             |
|       stats version:0                                                                                                                                                                      |
|       dynamic sampling level:1                                                                                                                                                             |
|       estimation method:[DYNAMIC SAMPLING FULL]                                                                                                                                            |
|   t2:                                                                                                                                                                                      |
|       table_rows:1                                                                                                                                                                         |
|       physical_range_rows:1                                                                                                                                                                |
|       logical_range_rows:1                                                                                                                                                                 |
|       index_back_rows:0                                                                                                                                                                    |
|       output_rows:1                                                                                                                                                                        |
|       table_dop:1                                                                                                                                                                          |
|       dop_method:Table DOP                                                                                                                                                                 |
|       avaiable_index_name:[t2]                                                                                                                                                             |
|       stats version:0                                                                                                                                                                      |
|       dynamic sampling level:1                                                                                                                                                             |
|       estimation method:[DYNAMIC SAMPLING FULL]                                                                                                                                            |
|   Plan Type:                                                                                                                                                                               |
|       LOCAL                                                                                                                                                                                |
|   Note:                                                                                                                                                                                    |
|       Degree of Parallelisim is 1 because of table property                                                                                                                                |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
97 rows in set

```

### USE_HASH Hint

`USE_HASH` 指定表作为右表，在联接的时候使用 Hash Join 算法，语法如下：

```sql
/*+ USE_HASH(table_name_list) */

```

示例如下：

```sql
obclient> CREATE TABLE t0(c1 INT, c2 INT, c3 INT);
obclient> CREATE TABLE t1(c1 INT, c2 INT, c3 INT);

obclient> EXPLAIN EXTENDED SELECT /*+LEADING(t0 t1) USE_HASH(t1)*/ *
FROM t0, t1 WHERE t0.c1 = t1.c1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                                                 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| =================================================                                                                                                                                          |
| |ID|OPERATOR         |NAME|EST.ROWS|EST.TIME(us)|                                                                                                                                          |
| -------------------------------------------------                                                                                                                                          |
| |0 |HASH JOIN        |    |1       |5           |                                                                                                                                          |
| |1 |├─TABLE FULL SCAN|t0  |1       |3           |                                                                                                                                          |
| |2 |└─TABLE FULL SCAN|t1  |1       |3           |                                                                                                                                          |
| =================================================                                                                                                                                          |
| Outputs & filters:                                                                                                                                                                         |
| -------------------------------------                                                                                                                                                      |
|   0 - output([t0.c1(0x7f21a8421640)], [t0.c2(0x7f21a8421f00)], [t0.c3(0x7f21a8422230)], [t1.c1(0x7f21a8421980)], [t1.c2(0x7f21a8422560)], [t1.c3(0x7f21a8422890)]), filter(nil), rowset=16 |
|       equal_conds([t0.c1(0x7f21a8421640) = t1.c1(0x7f21a8421980)(0x7f21a8420e80)]), other_conds(nil)                                                                                       |
|   1 - output([t0.c1(0x7f21a8421640)], [t0.c2(0x7f21a8421f00)], [t0.c3(0x7f21a8422230)]), filter(nil), rowset=16                                                                            |
|       access([t0.c1(0x7f21a8421640)], [t0.c2(0x7f21a8421f00)], [t0.c3(0x7f21a8422230)]), partitions(p0)                                                                                    |
|       is_index_back=false, is_global_index=false,                                                                                                                                          |
|       range_key([t0.__pk_increment(0x7f21a84230f0)]), range(MIN ; MAX)always true                                                                                                          |
|   2 - output([t1.c1(0x7f21a8421980)], [t1.c2(0x7f21a8422560)], [t1.c3(0x7f21a8422890)]), filter(nil), rowset=16                                                                            |
|       access([t1.c1(0x7f21a8421980)], [t1.c2(0x7f21a8422560)], [t1.c3(0x7f21a8422890)]), partitions(p0)                                                                                    |
|       is_index_back=false, is_global_index=false,                                                                                                                                          |
|       range_key([t1.__pk_increment(0x7f21a8423420)]), range(MIN ; MAX)always true                                                                                                          |
| Used Hint:                                                                                                                                                                                 |
| -------------------------------------                                                                                                                                                      |
|   /*+                                                                                                                                                                                      |
|                                                                                                                                                                                            |
|       LEADING(("t0" "t1"))                                                                                                                                                                 |
|       USE_HASH("t1")                                                                                                                                                                       |
|   */                                                                                                                                                                                       |
| Qb name trace:                                                                                                                                                                             |
| -------------------------------------                                                                                                                                                      |
|   stmt_id:0, stmt_type:T_EXPLAIN                                                                                                                                                           |
|   stmt_id:1, SEL$1                                                                                                                                                                         |
| Outline Data:                                                                                                                                                                              |
| -------------------------------------                                                                                                                                                      |
|   /*+                                                                                                                                                                                      |
|       BEGIN_OUTLINE_DATA                                                                                                                                                                   |
|       LEADING(@"SEL$1" ("dddd"."t0"@"SEL$1" "dddd"."t1"@"SEL$1"))                                                                                                                          |
|       USE_HASH(@"SEL$1" "dddd"."t1"@"SEL$1")                                                                                                                                               |
|       FULL(@"SEL$1" "dddd"."t0"@"SEL$1")                                                                                                                                                   |
|       FULL(@"SEL$1" "dddd"."t1"@"SEL$1")                                                                                                                                                   |
|       OPTIMIZER_FEATURES_ENABLE('4.3.0.0')                                                                                                                                                 |
|       END_OUTLINE_DATA                                                                                                                                                                     |
|   */                                                                                                                                                                                       |
| Optimization Info:                                                                                                                                                                         |
| -------------------------------------                                                                                                                                                      |
|   t0:                                                                                                                                                                                      |
|       table_rows:1                                                                                                                                                                         |
|       physical_range_rows:1                                                                                                                                                                |
|       logical_range_rows:1                                                                                                                                                                 |
|       index_back_rows:0                                                                                                                                                                    |
|       output_rows:1                                                                                                                                                                        |
|       table_dop:1                                                                                                                                                                          |
|       dop_method:Table DOP                                                                                                                                                                 |
|       avaiable_index_name:[t0]                                                                                                                                                             |
|       stats version:0                                                                                                                                                                      |
|       dynamic sampling level:1                                                                                                                                                             |
|       estimation method:[DYNAMIC SAMPLING FULL]                                                                                                                                            |
|   t1:                                                                                                                                                                                      |
|       table_rows:1                                                                                                                                                                         |
|       physical_range_rows:1                                                                                                                                                                |
|       logical_range_rows:1                                                                                                                                                                 |
|       index_back_rows:0                                                                                                                                                                    |
|       output_rows:1                                                                                                                                                                        |
|       table_dop:1                                                                                                                                                                          |
|       dop_method:Table DOP                                                                                                                                                                 |
|       avaiable_index_name:[t1]                                                                                                                                                             |
|       stats version:0                                                                                                                                                                      |
|       dynamic sampling level:1                                                                                                                                                             |
|       estimation method:[DYNAMIC SAMPLING FULL]                                                                                                                                            |
|   Plan Type:                                                                                                                                                                               |
|       LOCAL                                                                                                                                                                                |
|   Note:                                                                                                                                                                                    |
|       Degree of Parallelisim is 1 because of table property                                                                                                                                |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
71 rows in set

```

### PARALLEL Hint

`PARALLEL` 指定语句级别的并行度。语法如下：

```sql
/*+ PARALLEL(n) */

```

其中 `n` 为整数，表示并行度。

OceanBase 数据库也支持表级别的 `PARALLEL` Hint，语法如下：

```sql
/*+ PARALLEL(table_name n) */

```

如果同时指定了全局并行度和表级并行度，则表级并行度不会生效。示例如下：

```sql
obclient> CREATE TABLE tbl1 (col1 INT)  PARTITION BY HASH(col1) ;
Query OK, 0 rows affected

obclient> EXPLAIN SELECT /*+ PARALLEL(3) PARALLEL(tbl1 5) */ * FROM tbl1;
+----------------------------------------------------------------------+
| Query Plan                                                           |
+----------------------------------------------------------------------+
| =========================================================            |
| |ID|OPERATOR             |NAME    |EST.ROWS|EST.TIME(us)|            |
| ---------------------------------------------------------            |
| |0 |PX COORDINATOR       |        |1       |1           |            |
| |1 |└─EXCHANGE OUT DISTR |:EX10000|1       |1           |            |
| |2 |  └─PX BLOCK ITERATOR|        |1       |1           |            |
| |3 |    └─TABLE FULL SCAN|tbl1    |1       |1           |            |
| =========================================================            |
| Outputs & filters:                                                   |
| -------------------------------------                                |
|   0 - output([INTERNAL_FUNCTION(tbl1.col1)]), filter(nil), rowset=16 |
|   1 - output([INTERNAL_FUNCTION(tbl1.col1)]), filter(nil), rowset=16 |
|       dop=5                                                          |
|   2 - output([tbl1.col1]), filter(nil), rowset=16                    |
|   3 - output([tbl1.col1]), filter(nil), rowset=16                    |
|       access([tbl1.col1]), partitions(p0)                            |
|       is_index_back=false, is_global_index=false,                    |
|       range_key([tbl1.__pk_increment]), range(MIN ; MAX)always true  |
+----------------------------------------------------------------------+
18 rows in set

```

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
