---
title: Outline / Hint 常见问题-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于 Outline / Hint 常见问题相关的常见问题和使用技巧，帮助您快速解决 Outline / Hint 常见问题的难题。
image: https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*OSPzQ6GUQF4AAAAAQHAAAAgAeiGDAQ/original
---
切换语言

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

划线反馈

# Outline / Hint 常见问题

更新时间：2024-08-02 02:02

适用版本： V1.4.x、V2.1.x、V2.2.x、V3.1.x、V3.2.x、V4.0.x、V4.1.x、V4.2.x 内容类型：TechNote  

## 绑定 outline 失败原因排查

### 确认是否匹配 outline

确认 `gv$ob_plan_cache_plan_stat` (在 OceanBase 数据库 V4.x 之前版本为 `gv$plan_cache_plan_stat`) 视图中物理计划相关字段。

- OUTLINE_DATA: 完全描述了当前计划的计划形态，和 explain outline/explain extended 中 outline data含义相同。
 - HINTS_INFO: 生成该计划时使用的 hint，和 explain extended 中 used hint 含义相同。
 - OUTLINE_ID: 生成计划所使用的用户创建 outline id，-1 时表示没有使用用户创建 outline

  如果 OUTLINE_ID 为 -1 则创建的 outline 没有匹配到对应 sql 上，检查创建 outline 用户/sql id 等信息。

## 如何用 explain extended 验证 outline/hint 有效

将 outline data 添加到查询后（对于 OceanBase 数据库 V4.0 之前版本，还需要移除原始查询中的hint），使用 explain extended 查看计划是否符合预期及 used hint 是否包含所有 outline 中 hint。

```shell
 1. 待验证查询。
 create table t1(c1 int, c2 int);
 create index idx1 on t1(c1);
 create index idx2 on t1(c2);
 select /*+index(t1 idx1)*/ * from t1 where c1 > 2 and c2 < 4;
 create outline otl on 'xxxx' using hint
 /*+
       BEGIN_OUTLINE_DATA
       INDEX(@"SEL$1" "oceanbase"."t1"@"SEL$1" "idx2")
       OPTIMIZER_FEATURES_ENABLE('4.0.0.0')
       END_OUTLINE_DATA
 */

 2. explain 验证使用的 sql。
 explain extended
 select /*+
       BEGIN_OUTLINE_DATA
       INDEX(@"SEL$1" "oceanbase"."t1"@"SEL$1" "idx2")
       OPTIMIZER_FEATURES_ENABLE('4.0.0.0')
       END_OUTLINE_DATA
 */ * from t1 where c1 > 2 and c2 < 4;

 对于 explain extended 结果，除了查看计划，对比这两部分
 Used Hint:
 -------------------------------------
  /*+

  .....
    查看原始 outline data 中hint是否完全出现在这里
  */

 Outline Data:
 -------------------------------------
  /*+
      对比和待验证原始 outline data 是否一致
  */

```

#### 注意

对于 Q1:`select * from t1;` 和 Q2: `explain select * from t1;` 是完全不同的查询，使用 sql id 绑定在 Q1 上的 outline 不会直接作用在 Q2 上，因此不能直接通过 explain Q1 来验证 outline 是否有效。

## 手动添加 hint 失效常见问题

### MySQL 客户端连接, 连接串未添加 -c 导致 hint 失效

可以使用简单查询对这种情况进行识别验证，如查看一下查询计划是否开启并行。

```shell
create table t1(c1 int, c2 int);
explain select /*+parallel(2)*/ * from t1;

```

### hint 表对象指定无效

当表对象有别名时，必须使用别名指定。

- 使用别名指定，有效。

  ```shell
  select /*+index(a idx)*/ * from t1 a;

  ```
 - 使用非别名指定，无效。

  ```shell
  select /*+index(t1 idx)*/ * from t1 a;

  ```
 - 必须指定别名的原因（不使用别名会导致含义不明），如下面查询语句。

  ```shell
   select /*+index(t1 idx)*/ * from t1 a, t1 b ...;

  ```

### use_hash / use_merge / use_nl 等 hint 失效

hint 语义及语法参见：[Hint 概述](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000001054625)。

要使 use_hash 必然有效，一定要指定连接顺序。下面这种写法仅指定了以 t2 为右表时使用 hash join，最终可能生成以 t2 为左表的 merge join/nest loop join 计划。

```shell
select /*+use_hash(t2)*/ * from t1, t2 where t1.c1 = t2.c1;

```

需要按照下面查询，先指定连接顺序。

```shell
select /*+leading(t1) use_hash(t2)*/ * from t1, t2 where t1.c1 = t2.c1;

```

### qb_name 使用不当导致 hint 失效

qb_name 用于在查询中指定 hint 的生效 query block。如下方查询，表层查询和内层查询 qb_name 分别为 sel$1 与 sel$2，index(@sel$2 t1 idx) 写在表层 query block，但通过 sel$2 实际作用生效在内层 query block。

```shell
select /*+no_rewrite index(@sel$2 t1 idx) */ *
from (select * from t1 where c1 = 3);

```

因此，在创建视图时，不能直接在视图查询中通过 qb_name 指定 hint。

```shell
 create view v1 as select /*+index(@sel$1 t1 idx)*/ * from t1 where c1 = 3;

 hint 在原始视图中生效
 select /*+index(@sel$1 t1 idx)*/ * from t1 where c1 = 3;

 v1 中的 hint 已失效，因为此时 sel$1 为表层 query block 的 qb_name,表层 query block 中不存在 t1，因此 hint index(@sel$1 t1 idx) 失效。

 select /*+no_rewrite*/ * from v1;

```

推荐使用方法：视图中添加 hint 时，直接使用不添加 qb_name 的 hint。

如果需要绑定计划，直接使用业务实际查询的 sql_id 通过原始查询的 outline data 创建 outline。

```shell
create view v1 as select /*+index(t1 idx)*/ * from t1 where c1 = 3;

```

## 在 OceanBase 数据库 V4.x 之前版本中 outline 常见失效原因

### 查询触发了基于代价改写

在 OceanBase V4.x 之前版本 outline data 中没有记录优化器进行的查询改写（[部分改写 hint 说明](https://www.oceanbase.com/docs/enterprise-oceanbase-database-cn-10000000000947800)），当发生基于代价改写会导致 outline data 固定计划失败，频繁出现的几种代价改写。

- OR 展开。

  ```shell
  USE_CONCAT / NO_EXPAND

  ```
 - group by placement。

  ```shell
  PLACE_GROUP_BY / NO_PLACE_GROUP_BY

  ```
 - semi to inner。

  将 semi join 改写为 inner join 强制触发与禁止触发 hint：UNNEST / NO_UNNEST，需要添加在子查询的上层查询中，如下示例。

  ```shell
  select /*+unnest*/ * from t1 where exists (select * from t2 where t2.c1 = t1.c1);

  ```

  或

  ```shell
  select /*+unnest*/ * from t1 where t1.c1 in (select t2.c1 from t2);

  ```

  上述二种写法的查询语句可改写为如下形式。

  ```shell
  select * from t1, (select distinct t2.c1 v_c1 from t2) v where v_c1 = t1.c1;

  ```

  #### 注意

  OceanBase 数据库 V4.x 开始使用 `SEMI_TO_INNER / NO_SEMI_TO_INNER` hint 控制这一改写，并添加在子查询中。

## 适用版本

OceanBase 数据库所有版本。

上一篇

[PX 并发配置实践](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000001409779)

下一篇

[使用 SQL_ID 和 FORMAT_SQL_ID 来绑定执行计划的说明](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000005438226) ![有帮助](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) 咨询热线
