SQL Plan Management(SPM)是一种防止计划回退的机制,能够确保新生成的计划在经过验证后才被使用,以保证计划性能不断优化和更新。
OceanBase 数据库支持在线 SPM 演进机制,即当发现新生成的计划不在基线中时,就会立即自动启动一个演进任务进行计划演进,这样就可以在用户无需手动干预的情况下自动完成计划演进。
OceanBase 数据库的 SPM 使用 DBA_SQL_PLAN_BASELINES 和 DBA_SQL_MANAGEMENT_CONFIG 视图,以及 DBMS_SPM 系统包来管理执行计划。
SPM 的执行机制
SPM 基于 SQL Plan Baseline 实现,SQL Plan Baseline 是执行计划的一个基线,用于持久化存储已经验证过的执行计划信息(Outline Data 等信息),每个执行计划可对应一个 Plan Baseline,通过该 Plan Baseline 可复现一个执行计划。
OceanBase 数据库计划的演进总是由计划生成触发的,SPM 的执行机制的可以概括为:
- SQL 第一次生成的计划会被默认作为基线并被
ACCEPT。 - 当新的计划存在于计划基线中,并且基线是
FIXED或者不存在其它FIXED计划基线时,直接使用当前计划。 - 当存在可复现的
FIXED基线时,总是优先使用FIXED基线计划,不做计划演进。 - 当不存在可复现的
FIXED基线,但存在可复现的ACCEPTED基线计划,则新计划与基线计划进行演进。 - 如果没有基线计划可以复现,则直接使用新生成的计划。
SPM 的使用限制
OceanBase 数据库的 SPM 具有如下使用限制:
- 处于备份恢复的恢复状态的租户和主备集群的备机无法执行计划演进。
- 系统租户下的 SQL 和 Inner SQL 不能做计划演进。
- SQL 语句包含
INSERT INTO VALUES时不做计划演进。 - 由于演进的结果是暂存在 OBServer 的 Local Cache 中,会定期同步到 Inner Table 中,所以任何 OBServer 的演进结果对于其它的 OBServer 来讲是无法立即感知的。
SPM 相关视图
DBA_SQL_PLAN_BASELINES
DBA_SQL_PLAN_BASELINES 视图记录了 SPM 中 SQL 的计划基线。该视图各字段的含义如下表所示。
| 字段名称 | 数据类型 | 是否为 NULL | 说明 |
|---|---|---|---|
| SIGNATURE | VARCHAR2(128) | NOT NULL | 由归一化的 SQL 产生的 SQL 唯一标识符(这个字段的类型与 Oracle 不兼容)。 |
| SQL_HANDLE | VARCHAR2(128) | NOT NULL | 唯一的文本形式的 SQL 表示。 |
| SQL_TEXT | CLOB | NOT NULL | 未归一化的 SQL 文本。 |
| PLAN_NAME | VARCHAR2(128) | NOT NULL | 唯一的文本形式的计划标识符。 |
| CREATOR | VARCHAR2(128) | 创建这条计划基线的用户名称。 | |
| ORIGIN | VARCHAR2(14) | 计划基线的创建方式,如下:
| |
| PARSING_SCHEMA_NAME | VARCHAR2(128) | 恒为 NULL。 | |
| DESCRIPTION | VARCHAR2(500) | 计划基线的说明。 | |
| VERSION | VARCHAR2(64) | 计划基线创建时的数据库版本。 | |
| CREATED | TIMESTAMP(6) | NOT NULL | 计划基线的创建时间。 |
| LAST_MODIFIED | TIMESTAMP(6) | 计划基线上次的修改时间。 | |
| LAST_EXECUTED | TIMESTAMP(6) | 计划基线上次的执行时间。 | |
| LAST_VERIFIED | TIMESTAMP(6) | 计划基线上次的验证时间。 | |
| ENABLED | VARCHAR2(3) | 计划基线是启用的('YES')还是禁用的('NO')。 | |
| ACCEPTED | VARCHAR2(3) | 计划基线是被采纳的('YES')还是未被采纳的('NO')。 | |
| FIXED | VARCHAR2(3) | 计划基线是固定的('YES')还是非固定的('NO')。 | |
| REPRODUCED | VARCHAR2(3) | 计划基线是可复现的('YES')还是不可复现的('NO')。 | |
| AUTOPURGE | VARCHAR2(3) | 计划基线是自动清理的('YES')还是非自动清理的('NO')。 | |
| ADAPTIVE | VARCHAR2(3) | 由 SPM 自动捕获的计划基线是否已经是适应的。 | |
| OPTIMIZER_COST | NUMBER | 计划基线创建时优化器估计的计划代价。 | |
| MODULE | VARCHAR2(64) | 恒为 NULL。 | |
| ACTION | VARCHAR2(64) | 恒为 NULL。 | |
| EXECUTIONS | NUMBER | 计划基线创建时计划的执行次数。 | |
| ELAPSED_TIME | NUMBER | 计划基线创建时计划的总耗时。 | |
| CPU_TIME | NUMBER | 计划基线创建时计划的总 CPU 时间。 | |
| BUFFER_GETS | NUMBER | 恒为 NULL。 | |
| DISK_READS | NUMBER | 恒为 NULL。 | |
| DIRECT_WRITES | NUMBER | 恒为 NULL。 | |
| ROWS_PROCESSED | NUMBER | 恒为 NULL。 | |
| FETCHES | NUMBER | 恒为 NULL。 | |
| END_OF_FETCH_COUNT | NUMBER | 恒为 NULL。 |
DBA_SQL_MANAGEMENT_CONFIG
DBA_SQL_MANAGEMENT_CONFIG 视图记录了 SPM 中的配置参数。该视图各字段的含义如下表所示。
| 字段名称 | 数据类型 | 是否为NULL | 说明 |
|---|---|---|---|
| PARAMETER_NAME | VARCHAR2(128) | NOT NULL | 配置参数的名字。如下:
|
| PARAMETER_VALUE | NUMBER | NOT NULL | 配置参数的值。 |
| LAST_MODIFIED | TIMESTAMP(6) | 参数值上次更新的时间。 | |
| MODIFIED_BY | VARCHAR2(128) | 参数值上次由谁更新的。 |
DBMS_SPM 系统包
DBMS_SPM 系统包用于管理 SQL 计划,支持加载、更改以及删除 Plan Baseline 信息。
下表列出了 OceanBase 数据库当前版本所支持的 DBMS_SPM 子程序和简要描述。
| 子程序 | 描述 |
|---|---|
| ACCEPT_SQL_PLAN_BASELINE | 根据演进计划的结果接受一个计划作为基线。 |
| ALTER_SQL_PLAN_BASELINE | 修改基线中一个或一组计划的属性。返回值表示被修改的基线数量。 |
| CANCEL_EVOLVE_TASK | 取消一个正在演进的任务。 |
| CONFIGURE | 设置 SPM 的一些参数。 |
| DROP_EVOLVE_TASK | 丢弃一个演进任务。 |
| DROP_SQL_PLAN_BASELINE | 丢弃一个或多个计划基线。 |
| LOAD_PLANS_FROM_CURSOR_CACH | 从 Cursor Cache 中读取一条或多条 SQL 计划作为计划基线。 |
ACCEPT_SQL_PLAN_BASELINE
ACCEPT_SQL_PLAN_BASELINE 过程用于根据演进计划的结果接受一个计划作为基线。
语法
语法如下:
DBMS_SPM.ACCEPT_SQL_PLAN_BASELINE (
database_name VARCHAR(65535),
sql_handle VARCHAR(65535),
plan_name VARCHAR(65535) DEFAULT NULL);
参数说明
| 参数名称 | 说明 |
|---|---|
| database_name | 数据库名称,需要指定该参数。 |
| sql_handle | SQL 的标识符,也就是 SQL_ID。 |
| plan_name | 计划的名称,也就是 Plan Hash Value。如果值为 NULL,表示接受一个 SQL 所有正在演进的计划。 |
示例
DECLARE
v_accept_plans NUMBER;
BEGIN
v_accept_plans := DBMS_SPM.ACCEPT_SQL_PLAN_BASELINE(
sql_handle => '529F6E6454EF579C7CC265D1F6131D70',
plan_name => '3388268709115914355'
);
END;
/
ALTER_SQL_PLAN_BASELINE
ALTER_SQL_PLAN_BASELINE 函数用于修改基线中一个或一组计划的属性。返回值表示被修改的基线数量。
语法
语法如下:
DBMS_SPM.ALTER_SQL_PLAN_BASELINE (
database_name VARCHAR(65535),
sql_handle VARCHAR(65535),
plan_name VARCHAR(65535) DEFAULT NULL,
attribute_name VARCHAR(65535),
attribute_value VARCHAR(65535)
)
RETURN DECIMAL;
参数说明
| 参数名称 | 说明 |
|---|---|
| database_name | 数据库名称,需要指定该参数。 |
| sql_handle | SQL 的标识符,也就是 SQL_ID。 |
| plan_name | 计划的名称,也就是 Plan Hash Value。如果值为 NULL,表示接受一个 SQL 所有正在演进的计划。 |
| attribute_name | 计划的属性名称。请参见 属性说明。 |
| attribute_value | 计划的属性值。请参见 属性说明。 |
属性说明
| 属性名称 | 可取的属性值 | 描述 |
|---|---|---|
| enabled | 'YES' 或 'NO' | 'YES' 表示计划基线是有效的。最终计划基线是否会被使用取决于是否被接受。 |
| fixed | 'YES' 或 'NO' | 'YES' 表示优先使用当前计划基线,并且不进行自动演进。 |
| autopurge | 'YES' 或 'NO' | 'YES' 表示计划基线一段时候没有使用后会被自动淘汰;'NO' 表示计划基线永不淘汰。 |
| plan_name | 字符串,最多 30 个字符。 | 计划的名称。 |
| description | 字符串,最多 500 个字节。 | 计划的描述。 |
示例
将某个 Plan Baseline 固化后该 SQL 仅使用该计划。
DECLARE
v_alter_plans NUMBER;
BEGIN
v_alter_plans := DBMS_SPM.ALTER_SQL_PLAN_BASELINE(
sql_handle => '529F6E6454EF579C7CC265D1F6131D70',
plan_name => '3388268709115914355',
attribute_name => 'fixed',
attribute_value => 'YES' );
END;
/
CANCEL_EVOLVE_TASK
CANCEL_EVOLVE_TASK 过程用于取消一个正在演进的任务。
语法
语法:
DBMS_SPM.CANCEL_EVOLVE_TASK (
database_name VARCHAR(65535),
task_name VARCHAR(65535));
参数说明
| 参数名称 | 描述 |
|---|---|
| database_name | 数据库名称,仅 MySQL 模式下需要指定该参数。 |
| task_name | 任务名称,即当前 OceanBase 数据库中使用 SQL_ID 所表示的演进任务名称。 |
示例
BEGIN
DBMS_SPM.CANCEL_EVOLVE_TASK ('SYS_AUTO_SPM_EVOLVE_TASK');
END;
CONFIGURE
CONFIGURE 过程用于设置 SPM 的一些参数。
语法
语法如下:
DBMS_SPM.CONFIGURE (
database_name VARCHAR(65535),
parameter_name VARCHAR(65535),
parameter_value DECIMAL
);
参数说明
| 参数名称 | 说明 |
|---|---|
| database_name | 数据库名称,仅 MySQL 模式下需要指定该参数。 |
| parameter_name | 要设置的参数名称。请参见 SPM 参数说明。 |
| parameter_value | 要设置的参数值。请参见 SPM 参数说明。 |
SPM 参数说明
| SPM 参数名称 | 描述 | 可取的参数值 | 默认值 |
|---|---|---|---|
| space_budget_percent | 用于设置 SPM 的 SYSAUX 空间最大百分比。 | 1,2,...,50 | 10 |
| plan_retention_weeks | 设置计划几周后未被使用会被自动淘汰掉。 | 5,6,...,523 | 53 |
示例
设置计划 20 周后未被使用会被自动淘汰掉。
BEGIN
DBMS_SPM.CONFIGURE ('plan_retention_weeks', 20);
END;
DROP_EVOLVE_TASK
DROP_EVOLVE_TASK 过程用于丢弃一个演进任务。
语法
语法如下:
DBMS_SPM.DROP_EVOLVE_TASK (
database_name VARCHAR(65535),
task_name VARCHAR(65535));
参数说明
| 参数名称 | 说明 |
|---|---|
| database_name | 数据库名称,仅 MySQL 模式下需要指定该参数。 |
| task_name | 任务名称,即当前 OceanBase 数据库中使用 SQL_ID 所表示的演进任务名称。 |
示例
BEGIN
DBMS_SPM.DROP_EVOLVE_TASK ('SYS_AUTO_SPM_EVOLVE_TASK');
END;
DROP_SQL_PLAN_BASELINE
DROP_SQL_PLAN_BASELINE 函数用于用于丢弃一个或多个计划基线。
语法
语法如下:
DBMS_SPM.DROP_SQL_PLAN_BASELINE (
database_name VARCHAR(65535),
sql_handle VARCHAR(65535),
plan_name VARCHAR(65535) DEFAULT NULL
)
RETURN DECIMAL;
参数说明
| 参数名称 | 说明 |
|---|---|
| database_name | 数据库名称,仅 MySQL 模式下需要指定该参数。 |
| sql_handle | SQL 的标识符,也就是 SQL_ID。 |
| plan_name | 计划的名称,也就是 Plan Hash Value。如果值为 NULL,表示接受一个 SQL 所有正在演进的计划。 |
示例
DECLARE
v_drop_plans number;
BEGIN
v_drop_plans := DBMS_SPM.DROP_SQL_PLAN_BASELINE(
sql_handle => '529F6E6454EF579C7CC265D1F6131D70',
plan_name => '3388268709115914355' );
END;
/
LOAD_PLANS_FROM_CURSOR_CACHE
LOAD_PLANS_FROM_CURSOR_CACHE 函数用于用于从 Plan Cache 中读取一条或多条 SQL 的计划作为计划基线。
语法如下:
DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE (
database_name VARCHAR(65535),
sql_id VARCHAR(65535),
plan_hash_value DECIMAL DEFAULT NULL,
is_fixed VARCHAR(65535) DEFAULT 'NO',
enabled VARCHAR(65535) DEFAULT 'YES'
)
RETURN DECIMAL;
参数说明
| 参数名称 | 说明 |
|---|---|
| database_name | 数据库名称,仅 MySQL 模式下需要指定该参数。 |
| sql_id | 要加载的 SQL_ID。 |
| plan_hash_value | 要加载的计划的 Plan Hash Value。如果值为 NULL,加载 Plan Cache 中指定 SQL 的所有计划作为计划基线。 |
| is_fixed | 加载的计划基线的 is_fixed 属性。 |
| enabled | 加载的计划基线的 enabled 属性。 |
示例
DECLARE
v_load_plans number;
BEGIN
v_load_plans := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(
sql_id => '529F6E6454EF579C7CC265D1F6131D70',
plan_hash_value => 13388268709115914355);
END;
/



