暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

OceanBase管理数据库计划绑定(一)

2023-08-10
978

通过对某条 SQL 创建 Outline 可实现计划绑定。

在系统上线前,可以直接在 SQL 语句中添加 Hint,控制优化器按 Hint 指定的行为进行计划生成。

但对于已上线的业务,如果出现优化器选择的计划不够优化时,则需要在线进行计划绑定,即无需业务进行 SQL 更改,而是通过 DDL 操作将一组 Hint 加入到 SQL 中,从而使优化器根据指定的一组 Hint,对该 SQL 生成更优计划。该组 Hint 称为 Outline。

Outline 视图

Outline 视图为 DBA_OB_OUTLINES,其字段说明如下表所示。

字段名称类型描述
GMT_CREATETIMESTAMP(6)创建时间戳
GMT_MODIFIEDTIMESTAMP(6)修改时间戳
TENANT_IDBIGINT(20)租户 ID
DATABASE_IDBIGINT(20)数据库 ID
OUTLINE_IDBIGINT(20)Outline ID
DATABASE_NAMEVARCHAR2(128)数据库名称
OUTLINE_NAMEVARCHAR2(128)Outline 名称
VISIBLE_SIGNATURELONGTEXTSignature 的反序列化结果,为了便于查看 Signature 的信息。
SQL_TEXTLONGTEXT创建 Outline 时,在 ON 子句中指定的 SQL。
OUTLINE_TARGETLONGTEXT创建 Outline 时,在 TO 子句中指定的 SQL。
OUTLINE_SQLLONGTEXT具有完整 Outline 信息的 SQL
SQL_IDVARCHAR2(32)SQL 标识符
OUTLINE_CONTENTLONGTEXT完整的执行计划 Outline 信息

创建 Outline

OceanBase 数据库支持通过两种方式创建 Outline,一种是通过 SQL_TEXT (用户执行的带参数的原始语句),另一种是通过 SQL_ID 创建。

注意

创建 Outline 需要进入对应的数据库下执行。

使用 SQL_TEXT 创建 Outline

使用 SQL_TEXT 创建 Outline 后,会生成一个 Key-Value 对存储在 Map 中,其中 Key 为绑定的 SQL 参数化后的文本,Value 为绑定的 Hint。具体参数化原则,请参见 快速参数化

使用 SQL_TEXT 创建 Outline 的语法如下:

CREATE [OR REPLACE] OUTLINE <outline_name> ON <stmt> [ TO <target_stmt> ];

说明如下:

  • 指定 OR REPLACE 后,可以对已经存在执行计划进行替换。

  • 其中 stmt 一般为一个带有 Hint 和原始参数的 DML 语句。

  • 如果不指定 TO target_stmt,则表示如果数据库接受的 SQL 参数化后与 stmt 去掉 Hint 参数化文本相同,则将该 SQL 绑定 stmt 中 Hint 生成执行计划。

    如果期望对含有 Hint 的语句执行固定计划,则需要 TO target_stmt 来指明原始的 SQL。

    示例如下:

    obclient> CREATE OUTLINE outline1 ON SELECT /*+NO_REWRITE*/ * FROM tbl1 WHERE col1 = 4 
    AND col2 = 6 ORDER BY 2 TO SELECT  * FROM tbl1 WHERE col1 = 4 AND col2 = 6 ORDER BY 2;
    

注意

在使用 target_stmt 时,严格要求 stmt 与 target_stmt 在去掉 Hint 后完全匹配。

如下示例中,优化器选择了走主键扫描,如果数据量增大,如果执行索引 idx_c2,该 SQL 会更优化。此时可以通过创建 Outline 将该 SQL 绑定索引计划并执行。

obclient> CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT, c3 INT, INDEX idx_c2(c2));
Query OK, 0 rows affected  

obclient> INSERT INTO t1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3);
Query OK, 1 rows affected  

obclient> EXPLAIN SELECT * FROM t1 WHERE c2 = 1\G
*************************** 1. row ***************************
Query Plan: 
===================================
|ID|OPERATOR  |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|t1  |1        |37  |
===================================
Outputs & filters:
-------------------------------------
  0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c2 = 1]),
      access([t1.c2], [t1.c1], [t1.c3]), partitions(p0)

根据如下 SQL 语句创建 Outline:

obclient> CREATE OUTLINE otl_idx_c2 
       ON SELECT/*+ INDEX(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1;
Query OK, 0 rows affected 

使用 SQL_ID 创建 Outline

使用 SQL_ID 创建 Outline 的语法如下:

obclient> CREATE OUTLINE outline_name ON sql_id USING HINT hint_text;

SQL_ID 为需要绑定的 SQL 对应的 SQL_ID,可以通过以下方式获取:

  • 通过查询 gv$plan_cache_plan_stat 获取。

  • 通过查询 gv$sql_audit 获取。

  • 通过参数化的原始 SQL,使用 MD5 生成 SQL_ID 。可参考如下脚本生成对应 SQL 的 SQL_ID

    IMPORT hashlib
    sql_text='SELECT * FROM t1 WHERE c2 = ?'
    sql_id=hashlib.md5(sql_text.encode('utf-8')).hexdigest().upper()
    PRINT(sql_id)
    

使用 SQL_ID 绑定 Outline,如下例所示:

obclient> CREATE OUTLINE otl_idx_c2 ON "ED570339F2C856BA96008A29EDF04C74" 
USING HINT /*+ INDEX(t1 idx_c2)*/ ;

注意

  • Hint 格式为 /*+ xxx */,关于 Hint 说明的详细信息,请参见 Optimizer Hint。
  • 使用 SQL_TEXT 方式创建的 Outline 会覆盖 SQL_ID 方式创建的 Outline。SQL_TEXT 方式创建的优先级更高。
  • 如果 SQL_ID 对应的 SQL 语句已经有 Hint,则创建 Outline 指定的 Hint 会覆盖原始语句中所有 Hint。

Outline Data 是优化器为了完全复现某一计划而生成的一组 Hint 信息,以 BEGIN_OUTLINE_DATA 开始,并以 END_OUTLINE_DATA 结束。

Outline Data 可以通过 EXPLAIN EXTENDED 命令获得,如下例所示:

obclient> EXPLAIN EXTENDED SELECT/*+ index(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1\G
*************************** 1. row ***************************
Query Plan:
| =========================================
|ID|OPERATOR  |NAME      |EST. ROWS|COST|
-----------------------------------------
|0 |TABLE SCAN|t1(idx_c2)|1        |88  |
=========================================

Outputs & filters: 
-------------------------------------
  0 - output([t1.c1(0x7ff95ab37448)], [t1.c2(0x7ff95ab33090)], [t1.c3(0x7ff95ab377f0)]), filter(nil), 
      access([t1.c2(0x7ff95ab33090)], [t1.c1(0x7ff95ab37448)], [t1.c3(0x7ff95ab377f0)]), partitions(p0), 
      is_index_back=true, 
      range_key([t1.c2(0x7ff95ab33090)], [t1.c1(0x7ff95ab37448)]), range(1,MIN ; 1,MAX), 
      range_cond([t1.c2(0x7ff95ab33090) = 1(0x7ff95ab309f0)])

Used Hint:
-------------------------------------
  /*+
      INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
  */

Outline Data:
-------------------------------------
  /*+
      BEGIN_OUTLINE_DATA
      INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
      END_OUTLINE_DATA
  */

Plan Type:
-------------------------------------
LOCAL

Optimization Info:
-------------------------------------

t1:table_rows:3, physical_range_rows:1, logical_range_rows:1, index_back_rows:1, output_rows:1, est_method:local_storage, optimization_method=cost_based, avaiable_index_name[idx_c2], pruned_index_name[t1]
level 0:
***********
   paths(@1101710651081553(ordering([t1.c2], [t1.c1]), cost=87.951827))

其中 Outline Data 信息如下所示:

  /*+
      BEGIN_OUTLINE_DATA
      INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
      END_OUTLINE_DATA
  */

Outline Data 也属于 Hint,因此可以用在计划绑定的过程中,如下例所示:

obclient> CREATE OUTLINE otl_idx_c2 
     ON "ED570339F2C856BA96008A29EDF04C74" 
      USING HINT /*+
      BEGIN_OUTLINE_DATA
      INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
      END_OUTLINE_DATA
  */;
Query OK, 0 rows affected  
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论