千家信息网

sql plan baselines(一)

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,sql plan baselines在一个成熟的生产系统上,我们总是希望运行越稳定越好,执行计划越确定越好。但由于统计信息的变化、优化参数的修改、系统设置的修改、profile的创建等,都有可能造成执
千家信息网最后更新 2026年11月03日sql plan baselines(一)

sql plan baselines

在一个成熟的生产系统上,我们总是希望运行越稳定越好,执行计划越确定越好。但由于统计信息的变化、优化参数的修改、系统设置的修改、profile的创建等,都有可能造成执行计划的变化,从而性能上会有变化。这种变化不一定都是差的方向,比如优化器版本的升级,一般会使执行计划更加优化,但作为运维DBA,要确保万无一失,可能还是会相信自己。

为了应对可能的执行计划变化,oracle提供了baseline,我们翻译为基线,用于保证执行计划的稳定。

以下用实验来说明:

sql baseline有两种生成方式:

(1)需要通过AWR报告或者sql tuning set(STS)生成,因此,首先需要查看当前系统中可用的STS:

[oracle@localhost ~]$ sqlplus /nolog

SQL*Plus: Release 11.2.0.1.0 Production on Sun Dec 23 00:10:50 2012

Copyright (c) 1982, 2009, Oracle. All rights reserved.

SQL> conn scott/scott

Connected.

SQL> select * from dba_sqlset;

ID NAME OWNER DESCRIPTI CREATED LAST_MODI STATEMENT_COUNT

---------- ---------------------- -------------- --------------------------- ---------------- --------------------- ---------------------------

2 my_sql_tuningset SCOTT i/o intensive workload 22-DEC-12 22-DEC-12 0

SQL> declare

2 my_plans pls_integer;

3 begin

4 my_plans:=dbms_spm.load_plans_from_sqlset(sqlset_name=>'my_sql_tuningset');

5 end;

6 /

PL/SQL procedure successfully completed.

如果是从AWR报告中提取,则需要先用AWR报告生成STS,再执行以上步骤。

(2)从shared_pool_area中获取sql

比如我们刚刚执行了select * from dept where deptno=10,想要将此语句归入baseline中,操作如下:

SQL> select sql_id from v$sql where sql_text like 'select * from dept%';

SQL_ID

-------------

96kbu89824wkq

SQL> declare

2 my_plans pls_integer;

3 begin

4 my_plans:=dbms_spm.load_plans_from_cursor_cache(sql_id=>'96kbu89824wkq');

5 end;

6 /

PL/SQL procedure successfully completed.

每次数据库编译一条sql语句的时候,优化器首先基于成本找到最优的计划,然后在基线中查找是否有匹配的计划,如果找到了,就使用匹配的计划;如果没找到,就对基线中的计划进行比较,选出成本最低的。最开始产生的最优计划不会被使用,而是作为一个不可接受的计划放入计划历史中,如果由于系统变化使得所有基线中的计划都不可用,才会使用刚才选出来的最优计划。

如果oracle确认不可接受的计划不会造成性能问题(比基线中的计划性能好),就会将其放入基线中。

SQL> show parameter optimizer_use_sql

--此参数的值为true表示允许使用基线

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

optimizer_use_sql_plan_baselines boolean TRUE

SQL> set autot on

SQL> select * from dept where deptno=10;

DEPTNO DNAME LOC

---------- -------------- -------------

10 ACCOUNTING NEW YORK

Execution Plan

----------------------------------------------------------

Plan hash value: 2852011669

---------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 20 | 1 (0)| 00:00:01 |

| 1 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 20 | 1 (0)| 00:00:01 |

|* 2 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |

---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("DEPTNO"=10)

Note

-----

- SQL plan baseline "SQL_PLAN_1tkkvscv7fp020348d329" used for this statement

通过以上查询我们可以看到:语句使用了基线"SQL_PLAN_1tkkvscv7fp020348d329"

通过如下语句显示基线的内容:

SQL> select * from table(dbms_xplan.display_sql_plan_baseline(

2 plan_name=>'SQL_PLAN_1tkkvscv7fp020348d329',format=>'basic'));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

SQL handle: SYS_SQL_1cca5bc336775402

SQL text: select * from dept where deptno=10

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

Plan name: SQL_PLAN_1tkkvscv7fp020348d329 Plan id: 55104297

Enabled: YES Fixed: NO Accepted: YES Origin: MANUAL-LOAD

--------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 2852011669

-----------------------------------------------

| Id | Operation | Name |

-----------------------------------------------

| 0 | SELECT STATEMENT | |

| 1 | TABLE ACCESS BY INDEX ROWID| DEPT |

| 2 | INDEX UNIQUE SCAN | PK_DEPT |

-----------------------------------------------

20 rows selected.

里面包含了语句的内容、执行计划等信息。

如果不知道plan_name,可以通过如下方式获得:

select * from dba_sql_plan_baselines;

下面我们看一下在索引被删除,无法用baseline的情况能否正常运行语句,对基线是否有影响:(仅用于实验,实际中不要删除主键)

SQL> alter table dept drop index PK_DEPT;

alter table dept drop index PK_DEPT

*

ERROR at line 1:

ORA-00905: missing keyword

SQL> drop index PK_DEPT;

drop index PK_DEPT

*

ERROR at line 1:

ORA-02429: cannot drop index used for enforcement of unique/primary key

--由于存在主键约束,无法删除索引

SQL> alter table dept drop constraint pk_dept;

alter table dept drop constraint pk_dept

*

ERROR at line 1:

ORA-02273: this unique/primary key is referenced by some foreign keys

--由于存在外键约束,无法删除主键

SQL> drop table emp;

Table dropped.

SQL> alter table dept drop constraint pk_dept;

Table altered.

SQL> set autot on

SQL> select * from dept where deptno=10;

DEPTNO DNAME LOC

---------- -------------- -------------

10 ACCOUNTING NEW YORK

Execution Plan

----------------------------------------------------------

Plan hash value: 3383998547

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 20 | 3 (0)| 00:00:01 |

|* 1 | TABLE ACCESS FULL| DEPT | 1 | 20 | 3 (0)| 00:00:01 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("DEPTNO"=10)

--没办法使用基线,只能全表扫描了。那么这时的基线还存在吗?

SQL> select plan_name from dba_sql_plan_baselines;

PLAN_NAME

------------------------------

SQL_PLAN_1tkkvscv7fp020348d329

SQL_PLAN_1tkkvscv7fp020e23be79

SQL_PLAN_dxw60bwfynb5h0e23be79

--基线依然存在

尽管如此,但我们重新建立索引pk_dept后,基线还是不能用了:

SQL> create index pk_dept on dept(deptno);

Index created.

SQL> select * from dept where deptno=10;

DEPTNO DNAME LOC

---------- -------------- -------------

10 ACCOUNTING NEW YORK

Execution Plan

----------------------------------------------------------

Plan hash value: 2985873453

---------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 20 | 2 (0)| 00:00:01 |

| 1 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 20 | 2 (0)| 00:00:01 |

|* 2 | INDEX RANGE SCAN | PK_DEPT | 1 | | 1 (0)| 00:00:01 |

---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("DEPTNO"=10)

通过手工方式,可以将我们认为性能没有问题的执行计划(对应的基线)插入到系统基线中,这时候oracle并不会检查插入的基线性能是否真的好。

我们将上面的语句使用全表扫描查询,并将其生成基线

SQL> set autot on

SQL> select /*+full(dept)*/* from dept where deptno=10;

DEPTNO DNAME LOC

---------- -------------- -------------

10 ACCOUNTING NEW YORK

Execution Plan

----------------------------------------------------------

Plan hash value: 3383998547

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 20 | 3 (0)| 00:00:01 |

|* 1 | TABLE ACCESS FULL| DEPT | 1 | 20 | 3 (0)| 00:00:01 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("DEPTNO"=10)

SQL> select sql_id from v$sql where sql_text like 'select /*+full(dept)*/* from dept%';

SQL_ID

-------------

1gbphzt5d0159

SQL> declare

2 plan pls_integer;

3 begin

4 plan:=dbms_spm.load_plans_from_cursor_cache(sql_id=>'1gbphzt5d0159');

5 end;

6 /

PL/SQL procedure successfully completed.

然而这个语句并不会被select * from dept where deptno=10;使用到。即使是下面的语句也不能用到基线:

SQL> select /*+full(dept)*/* from dept where deptno='10';

DEPTNO DNAME LOC

---------- -------------- -------------

10 ACCOUNTING NEW YORK

Execution Plan

----------------------------------------------------------

Plan hash value: 3383998547

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 20 | 3 (0)| 00:00:01 |

|* 1 | TABLE ACCESS FULL| DEPT | 1 | 20 | 3 (0)| 00:00:01 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("DEPTNO"=10)

Oracle认为两个语句是不同的,只有在除了空格数以外完全相同的语句,才算是同一个语句。

如何删除一个基线呢?

dbms_spm中只提供了drop_sql_plan_baseline函数

找到dbms_spm的源码,该函数的声明为:

FUNCTION drop_sql_plan_baseline( sql_handle IN VARCHAR2 := NULL,
plan_name IN VARCHAR2 := NULL
)
RETURN PLS_INTEGER;

因此需要定义一个pls_integer类型的变量去接受结果:

SQL> declare

ret pls_integer;

begin

ret:=dbms_spm.drop_sql_plan_baseline(sql_handle=>'SYS_SQL_1cca5bc336775402',

plan_name=> 'SQL_PLAN_1tkkvscv7fp020348d329');

end;

/ 2 3 4 5 6

PL/SQL procedure successfully completed.

SQL> select plan_name from dba_sql_plan_baselines;

PLAN_NAME

------------------------------

SQL_PLAN_1tkkvscv7fp020e23be79

SQL_PLAN_1tkkvscv7fp02da6909c3

SQL_PLAN_dxw60bwfynb5h0e23be79

--可以看到,SQL_PLAN_1tkkvscv7fp020348d329被删除了

本次主要讲了baseline的生成、查看和删除。Baseline对于系统中sql的稳定性、性能有重要作用,因此下一部分实验baseline的导入、导出等。

如果在创建索引之前为语句创建了基线,然后创建索引。这时候,走索引进行查询可能比全表扫描要高效。

基线 语句 性能 系统 索引 变化 生成 报告 方式 实验 查询 信息 内容 函数 参数 成本 还是 选出 问题 面的 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 北京路客互联网科技有限公司 互联网属科技 善班互联网科技 上海喔噻互联网科技 汇久创客互联网科技 多迪互联网科技有限公司 科技伦理 互联网公司 无锡溥仪互联网科技有限公司 恒生科技互联网指数分析 汽车互联网创新科技园 智腾互联网科技有限公司 互联网科技大奖都有哪些公司 企晟互联网信息科技有限公司 深圳互联网科技的发展 广州百诚互联网科技有限公司官网 西安有哪些互联网高科技企业 广州梦谷互联网科技有限公司领导 互联网科技机房 科技美学互联网 艺术 前海云享互联网科技 互联网科技工作委员会主任 中国互联网科技工作委员会毛军 互联网科技官网 互联网科技公司的优势 北京互联网科技 上海宁丞科技互联网 互联网科技革命什么开始 深圳育鹏互联网科技有限公司招聘 互联网科技公司营业执照怎么办理 上海乐五互联网科技有限公司
0