---
title: "快速参数化 - OceanBase 数据库 V4.5.0 | OceanBase 文档中心"
description: 快速参数化 参数化过程是指把 SQL 查询中的常量变成变量的过程。 基于快速参数化获取执行计划 同一条 SQL 语句在每次执行时可能会使用不同的参数，将这些参数做参数化处理，可以得到与具体参数无关的 SQL 字符串，并使用该字符串作为计划缓存的键值，用于在计划缓存中获取执行计划，从而达到参数不同的 SQL 能够共用相…
---
切换语言

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

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

# 快速参数化

更新时间：2026-03-29 09:35:43

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.5.0/zh-CN/700.reference/1000.performance-tuning-guide/500.sql-optimization/200.sql-execution-plan/400.fast-parameterization.md)  

参数化过程是指把 SQL 查询中的常量变成变量的过程。

## 基于快速参数化获取执行计划

同一条 SQL 语句在每次执行时可能会使用不同的参数，将这些参数做参数化处理，可以得到与具体参数无关的 SQL 字符串，并使用该字符串作为计划缓存的键值，用于在计划缓存中获取执行计划，从而达到参数不同的 SQL 能够共用相同的计划目的。

由于传统数据库在进行参数化时一般是对语法树进行参数化，然后使用参数化后的语法树作为键值在计划缓存中获取计划，而 OceanBase 数据库使用的词法分析对文本串直接参数化后作为计划缓存的键值，因此叫做快速参数化。

基于快速参数化而获取执行计划的流程如下图所示：

![p179646](https://help-static-aliyun-doc.aliyuncs.com/assets/img/zh-CN/2936018461/p422452.jpg)

基于快速参数化的执行计划缓存优点如下：

- 节省了语法分析过程。
 - 查找 Hash Map 时，可以将对参数化后语法树的哈希和比较操作，替换为对文本串进行哈希和 `MEMCMP` 操作，以提高执行效率。

## 常量参数化及约束条件

在 OceanBase 数据库中，某些场景中的常量不能参数化，即参数化的约束条件如下：

- 所有 `ORDER BY` 后常量（例如 `ORDER BY 1,2;`）。
 - 所有 `GROUP BY` 后常量（例如 `GROUP BY 1,2;`）。
 - 作为格式串的字符串常量（例如 SQL 语句 `SELECT DATE_FORMAT('2006-06-00', '%d');` 中的`%d`）。
 - 函数输入参数中，影响函数结果并最终影响执行计划的常量（例如 SQL 语句 `CAST(999.88 as NUMBER(2,1))` 中的 `NUMBER(2,1)`，或者 `SUBSTR('abcd', 1, 2)` 中的 `1` 和 `2`）。
 - 函数输入参数中，带有隐含信息并最终影响执行计划的常量（例如 SQL 语句 `SELECT UNIX_TIMESTAMP('2015-11-13 10:20:19.012');` 中的"2015-11-13 10:20:19.012"，指定输入时间戳的同时，隐含指定了函数处理的精度值为毫秒）。

### 一般常量参数化示例

现有 SQL 查询语句示例如下：

```sql
obclient> SELECT * FROM t1 WHERE c1 = 5 AND c2 ='oceanbase';

```

上述示例中的 SQL 查询在 OceanBase 数据库内部进行参数化处理后结果如下所示，常量 `5` 和 `oceanbase` 被参数化后变成了变量 `@1` 和 `@2`，并对比当前数据库里已执行过的 SQL，并匹配对应的执行计划。

```sql
obclient> SELECT * FROM T1 WHERE c1 = @1 AND c2 = @2;

```

### 常量不支持参数化示例

但在计划匹配中，不是所有常量都可以被参数化，例如 `ORDER BY` 后面的常量，表示按照 `SELECT` 投影列中第几列进行排序，所以不可以被参数化。

创建示例表 `t1` 并插入适当的数据，表 `t1` 中包含 `c1`、`c2` 列，其中 `c1` 为主键列。

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

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

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

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

```

- 执行如下 SQL 查询，将结果按照 `c1` 列进行排序，由于 `c1` 作为主键列是有序的，所以使用主键访问可以免去排序。

  ```sql
  obclient> SELECT c1, c2 FROM t1 ORDER BY 1;
  +----+------+
  | C1 | C2   |
  +----+------+
  |  1 |    2 |
  |  2 |    1 |
  |  3 |    1 |
  +----+------+
  3 rows in set

  obclient> EXPLAIN SELECT c1, c2 FROM t1 ORDER BY 1;

  Query Plan:
  | ===================================
  |ID|OPERATOR  |NAME|EST. ROWS|COST|
  -----------------------------------
  |0 |TABLE SCAN|t1  |1000     |1381|
  ===================================
  Outputs & filters:
  -------------------------------------
    0 - output([T1.C1], [T1.C2]), filter(nil),
        access([T1.C1], [T1.C2]), partitions(p0)

  ```
 - 执行如下 SQL 查询，将结果按照 `c`2 列进行排序，则需要执行显示的排序操作，执行计划如下例所示：

  ```sql
  obclient> SELECT c1, c2 FROM t1 ORDER BY 2;
  +----+------+
  | C1 | C2   |
  +----+------+
  |  2 |    1 |
  |  3 |    1 |
  |  1 |    2 |
  +----+------+
  3 rows in set

  obclient> EXPLAIN SELECT c1, c2 FROM t1 ORDER BY 2;

  Query Plan:
  | ====================================
  |ID|OPERATOR   |NAME|EST. ROWS|COST|
  ------------------------------------
  |0 |SORT       |    |1000     |1886|
  |1 | TABLE SCAN|t1  |1000     |1381|
  ====================================
  Outputs & filters:
  -------------------------------------
    0 - output([T1.C1], [T1.C2]), filter(nil), sort_keys([T1.C2, ASC])
    1 - output([T1.C1], [T1.C2]), filter(nil),
        access([T1.C1], [T1.C2]), partitions(p0)

  ```

因此，如果将 `ORDER BY` 后面的常量参数化，不同 `ORDER BY` 的值具有相同的参数化后的 SQL，从而导致命中错误的计划。

### 解决常量参数化的误匹配问题

为了解决常量参数化中可能存在的误匹配问题，在硬解析生成执行计划过程中会对 SQL 请求使用分析语法树的方法进行参数化，并获取相应的不一致的信息。例如，某语句对应的信息是"快速参数化参数数组的第 3 项必须为数字 3"，可将其称为"约束条件"。

对于 Q1 查询 `SELECT c1, c2, c3 FROM t1 WHERE c1 = 1 AND c2 LIKE 'senior%' ORDER BY 3;`，经过词法分析，可以得到参数化后的 SQL 语句如下所示，参数化数组为 {1，'senior%'，3}。

```sql
obclient> SELECT c1, c2, c3 FROM t1 WHERE c1 = @1 AND c2 LIKE @2 ORDER BY @3;

```

当 `ORDER BY` 后面的常量不相同时，不能共用相同的执行计划，因此在通过分析语法树进行参数化时会获得另一种参数化结果。如下例所示，Q1 查询对应的参数化数组为 {1，'senior'}，约束条件为"快速参数化参数数组的第 3 项必须为数字 3"。OceanBase 数据库将 Q1 查询新生成的参数化后的文本及约束条件和执行计划均会存入计划缓存中。

```sql
obclient> SELECT c1, c2, c3 FROM t1 WHERE c1 = @1 AND c2 LIKE @2 ORDER BY 3;

```

当用户再次发出 Q2 查询命令 `SELECT c1, c2, c3 FROM t1 WHERE c1 = 1 AND c2 LIKE 'senior%' ORDER BY 2;` 时，经过快速参数化后结果如下例所示，对应的参数化数组为 {1，'senior%'，2}。

```

这与 Q1 查询快速参数化后 SQL 结果一样，但由于不满足"快速参数化参数数组的第 3 项必须为数字 3"这个约束条件，就无法匹配该计划。此时 Q2 会通过硬解析生成新的执行计划及约束条件（即"快速参数化参数数组的第 3 项必须为数字 2"），并将新的计划和约束条件加入到计划缓存中，这样在下次执行 Q1 和 Q2 时均可命中对应正确的执行计划。

## 参数化执行计划的区分策略

OceanBase 数据库还支持通过 Hint 控制是否对 SQL 语句中的字面量做参数改写，详细信息参见 [CURSOR_SHARING_EXACT Hint](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004481720)。

对于一条 SQL 请求，使用如下策略区分此条 SQL 要命中参数化的计划还是要命中非参数化的计划：

1. 查看 `cursor_sharing`

   首先查看 `cursor_sharing` 系统变量，具有不同 `cursor_sharing` 的 SQL 一定会命中到不同的计划。请参见 [cursor_sharing](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000004478661)。
 2. 查看 `query_sql`

   如果 `cursor_sharing` 变量无法帮助我们辨别出是否为参数化计划时，则说明 `cursor_sharing` 属于 `EXACT` 模式是由 `CURSOR_SHARING_EXACT` Hint 控制的，由于添加了 Hint 就会影响到 `query_sql` 的生成，因此，我们可以通过 `query_sql` 来区分参数化计划和非参数化计划。`query_sql` 可以通过 `GV$OB_SQL_AUDIT` 或者 `GV$OB_PLAN_CACHE_PLAN_STAT` 视图查看。

 上一篇 下一篇 ![有帮助](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) 咨询热线
