Oracle SQL Profile及SPM使用

IT数据库行业小学生,记录日常工作中数据库知识及一些故障案例,如有不对请指正,欢迎关注小编,小编微信xh870545795,CSDN:dba_notes5448f06e35efb7479c2a82e4b255a5bf.jpeg


一、区别

       我们知道oracle稳定执行计划有两种方式,一种是使用SQL profile(oracle 10g以前通常使用这种方式),还有一种是SPM(SQL Plan Management,oracle 11g推出的新功能),两者的主要区别是什么呢?

      通俗来讲,由于某些原因,比如统计信息陈旧导致优化器对执行计划的错误选择,导致sql的执行计划发生变更,此时可以通过创建SQL Profile来纠正、稳定这些sql的执行计划。但是通过SQL Profile固定执行计划后,依然不能保证系统后续执行的sql的执行计划就不再发生不好的变更。如果绑定的执行计划在后续不再适用此sql,那么依然会产生性能问题。因此在oracle 11g 推出了SPM,通俗来讲,SPM绑定执行计划后,会以此执行计划作为基线,当sql的执行计划产生变更,如果我们验证了变更的执行计划效率高于基线,那么才会启用此执行计划。

二、Sql Profile实验

实验环境为oracle 11.2.0.1.0 WINDOWS

1.创建测试表并插入数据

create table xh_test as select * from dba_objects;
insert into xh_test select * from xh_test;--尽量多插入些数据

2.查看当前查询语句的执行计划

测试语句:select * from xh_test where owner='PUBLIC';

查看执行计划:

SQL> set timing on;
SQL> set autotrace traceonly;
SQL> select * from xh_test where owner='PUBLIC';

3aeca247f622a6a87bb15a755606e2f8.png

3.创建索引、收集统计信息并查看计划

SQL> create index xh_test_owner_idx on xh_test(owner);
SQL> execute dbms_stats.gather_table_stats(ownname => 'SCOTT',tabname =>'XH_TEST',estimate_percent => 100,degree => 4,cascade => true, method_opt => 'for all columns size repeat');

101acd88ce35392568f89beddb69fbae.png

可见,建完索引,oracle优化器选择走索引,但速度并没有走全表的快,是因为owner列数据重复率高,索引扫描速度还没全表快。

4.使用Sql Profile绑定执行计划

4.1 使用hint方式强制走全表扫

select /*+ full(xh_test)*/* from xh_test where owner='PUBLIC';

6a5076455359785b06f3b17fc0fff109.png

4.2 绑定走全表扫的执行计划

4.2.1 查询sql_id 及PLAN_HASH_VALUE

select sql_text,sql_id,PLAN_HASH_VALUE from v$sql where sql_text like '%from xh_test where owner%';

d876c75b3462fbce59cfc03578651c53.png

通过上面的执行计划可得走全表扫的PLAN_HASH_VALUE为2771665069,对应的sql_id如上图所示为5km454qb6pvxq,走索引的PLAN_HASH_VALUE为1865429603,对应的sql_id如上图所示为akanjz3tzph8y

4.2.2绑定全表扫的执行计划到sql_id为akanjz3tzph8y的sql上

declare
ar_profile_hints sys.sqlprof_attr;
cl_sql_text clob;
begin
select extractvalue(value(d), '/hint') as outline_hints
bulk collect into ar_profile_hints
from xmltable('/ */outline_data/hint' passing
(select xmltype(other_xml) as xmlval
from v$sql_plan
where sql_id = '5km454qb6pvxq'    --执行效率高的sql_id(sql_id可以和下面的相同,因为有存在同样的sql_id有不同的执行计划的情况)
and PLAN_HASH_VALUE = 2771665069 --执行效率高的的sql_id hash value
and rownum=1
and other_xml is not null)) d;
select sql_fulltext
into cl_sql_text
from v$sql
where sql_id = 'akanjz3tzph8y'     --原始SQL(效率差)的sql_id
and rownum=1
and PLAN_HASH_VALUE = 1865429603;   --原始SQL(效率差)的hash value
dbms_sqltune.import_sql_profile(sql_text => cl_sql_text,
profile => ar_profile_hints,
name => 'profile_akanjz3tzph8y_sql', ---自定义名称,不能和现有的冲突
force_match => true,
replace => true);
end;
/

83e61ff21fcc69c0dbdf02c3340f1c89.png

验证:

822522b80be8abfbe602bc6fb371772a.png

4.2.3 其他操作

查看绑定sql_profile

select * from dba_sql_profiles;

删除Sql Profile

begin
dbms_sqltune.drop_sql_profile(
name => 'profile_akanjz3tzph8y_sql'); ---自定义名称,不能和现有的冲突
end;
/

三、SPM实验

3.1模拟一条sql语句多个执行计划

测试sql和上面一样,清除表上的Sql Profile,方法如上

select * from xh_test where owner='PUBLIC';

修改表上索引的聚簇因子,目的是为了能让SQL的执行计划变为对表xh_test的全表扫描(为何修改聚簇因子,参考http://www.linuxidc.com/Linux/2017-02/141071.htm )。修改完后再执行上述SQL,并查看执行计划:

SQL> exec dbms_stats.set_index_stats(ownname=>'SCOTT',indname=>'XH_TEST_OWNER_IDX',clstfct=>2400000,no_invalidate=>false);
PL/SQL 过程已成功完成。
SQL> select index_name,clustering_factor from dba_indexes where index_name='XH_TEST_OWNER_IDX';
INDEX_NAME                     CLUSTERING_FACTOR
------------------------------ -----------------
XH_TEST_OWNER_IDX                        2400000

bb65a13d96de5f81a1059c8ddc338dcd.png

此时走了全表扫描,查看对应的sql_id和plan hash value

select sql_text,sql_id,PLAN_HASH_VALUE from v$sql where sql_text like '%from xh_test where owner%';

ee04551bbdfe38e0e51923aec757f5fa.png

SELECT sql_id,plan_hash_value,operation,options FROM v$sql_plan WHERE sql_id='akanjz3tzph8y';

d8752752dde8e89757e1d81452dc9400.png

3.2 绑定SPM

将认为好的执行计划装载到执行计划管理器(创建基线):

variable retrst number;
exec :retrst:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'akanjz3tzph8y',plan_hash_value => 2771665069);

查询基线:

select sql_handle, plan_name,ENABLED,ACCEPTED, origin,SQL_TEXT from dba_sql_plan_baselines;

27dcdf677808369ea1ff1ee6dbc23041.png

enabled和accepted同为yes,对应的执行计划才会被启用,同样我们可以把走索引的执行计划也装载到执行计划管理器中然后不起用:

exec :retrst:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'akanjz3tzph8y',plan_hash_value => 1865429603);

39ea66129195bfb82ecac99b93ad1f52.png

注意,所有手工生成的SQL Plan Baseline的ENABLED和ACCEPTED的值均为YES

设置ENABLED的值设为NO

exec :retrst:= dbms_spm.alter_sql_plan_baseline(sql_handle=>'SYS_SQL_32a0a9efb3dd9b5b',plan_name=>'SQL_PLAN_35859xytxv6uv90f15403',attribute_name=>'enabled',attribute_value=>'NO');

76278459c392a81c7d596fcc4e2b300f.png

查看SQL装载到执行计划管理器的执行计划:

select * from table(dbms_xplan.display_sql_plan_baseline(plan_name=>'SQL_PLAN_35859xytxv6uv4d4d47db',format=>'basic'));

af9ea541333285244faaefe73160f0de.png

再次查看执行计划,显示SPM已经启用,将索引的聚簇因子修改回来仍然走全表扫。

3fb5b49d9ab7e7c3db0f17ea8f3a58b6.png

3.3 自动捕获SQL Plan Baseline

       参数OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES用于控制是否开启自动捕获SQL Plan Baseline,其默认值为FALSE,表示在默认情况下,Oracle并不会自动捕获SQL Plan Baseline。这个参数可以在session或系统级别动态修改。当修改为TRUE后,则Oracle会对上述参数影响范围内所有重复执行的SQL自动捕获其SQL Plan Baseline,并且针对目标SQL第一次捕获的SQL Plan Baseline的ENABLED和ACCEPTED的值均为“YES”。随后如果该SQL的执行计划发生了变更,则再次捕获到的SQL Plan Baseline的ENABLED的值依然为YES,但ACCEPTED的值变为了NO,这表示后续变更的执行计划虽然被捕获了,但Oracle不会将其作为该SQL的执行计划来执行,即此时Oracle会永远沿用该SQL第一次被捕获的SQL Plan Baseline所对应的执行计划(除非后续做了手工调整)。

       参数OPTIMIZER_USE_SQL_PLAN_BASELINES用于控制是否启用SQL Plan Baseline,其默认值为TRUE,表示在默认情况下,Oracle在生成执行计划时就会启用SPM,使用已有的SQL Plan Baseline,这个参数也可以在session或系统级别动态修改。

9a0d5a9b409fd07c867e88342c53383c.png

 3.4 其他操作命令

SPM删除:

variable retrst number;
exec :retrst:=dbms_spm.drop_sql_plan_baseline(sql_handle => 'SYS_SQL_097094edc8b9486b',plan_name=>'SQL_PLAN_0kw4nxr4bkk3b2a45d6aa');

设置对应的SQL Plan Baseline的ACCEPTED值设为YES:

var temp varchar2(1000);
exec :temp:= dbms_spm.evolve_sql_plan_baseline(sql_handle=>'SYS_SQL_356e77773103ae41',plan_name=>'SQL_PLAN_3avmrfwsh7bk19a1f256e',verify=>'NO',commit=>'YES');

   本次就分享到这里,如有不对,请指正,谢谢!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dba_notes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值