一、前言

前面文章(https://www.cnblogs.com/ddzj01/p/11365541.html)给大家介绍了当一条sql有多个执行计划时,如何通过spm去绑定其中一条执行计划。本文将继续介绍,如何给一条sql注入一个新的执行计划,去替换原始的执行计划。

二、解决办法

1. 生成初始执行计划所对应的sql plan baseline

begin
:temp := dbms_spm.load_plans_from_cursor_cache(
sql_id => '原目标sql的sql_id',
plan_hash_value => 原目标sql的plan hash value);
end;
/

2. 查出该sql的sql_handle

select sql_handle, sql_text, plan_name, origin from dba_sql_plan_baselines where sql_text like '原目标sql的sql_text%';

3. 生成新的sql plan baseline

begin
:temp := dbms_spm.load_plans_from_cursor_cache(
sql_id => '加入合适hint后改写的sql的sql_id',
plan_hash_value => 加入合适hint后改写的sql的plan hash value,
sql_handle => '原目标sql在步骤(1)中所产生的sql_handle');
end;
/

4. 删除步骤(1)中所产生的sql plan baseline

begin
:temp := dbms_spm.drop_sql_plan_baseline(
sql_handle => '原目标sql在步骤(1)中的sql_handle',
plan_name => '原目标sql在步骤(1)中的plan_name');
end;
/

就这么写,肯定一脸懵逼,下面通过一个实验去解释。

三、做个实验

实验环境,使用scott账号,并给scott赋予dba权限(实际上scott只需要administer sql management object权限就可以使用spm)

创建表和索引,并收集统计信息

SQL> create table test2 as select * from dba_objects;
SQL> create index idx_test2 on test2(object_id) online;

SQL> begin
dbms_stats.gather_table_stats(ownname=>'SCOTT',
tabname=>'TEST2',
cascade=>true,
no_invalidate=>false);
end;
/

执行原始的sql

SQL> set autot trace
SQL> select * from test2 where object_id=20;

Execution Plan
----------------------------------------------------------
Plan hash value: 4047680367 -----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 98 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST2 | 1 | 98 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_TEST2 | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

可以看到原始sql的执行计划为索引范围扫描

新开一个窗口,查原始sql的sql_id和plan_hash_value

SQL> col sql_id for a20
SQL> col sql_text for a40
SQL> select sql_id, plan_hash_value, sql_text from v$sqlarea where sql_text like 'select * from test2 where object_id=20%';

SQL_ID               PLAN_HASH_VALUE SQL_TEXT
-------------------- --------------- ----------------------------------------
4tm6j886yvzj3 4047680367 select * from test2 where object_id=20

将原始sql语句加入基线

SQL> var temp number;
SQL> begin 
:temp := dbms_spm.load_plans_from_cursor_cache(sql_id=>'4tm6j886yvzj3', plan_hash_value=>4047680367);
end;
/

查看原始sql的基线

SQL> col sql_handle for a24
SQL> col sql_text for a40
SQL> col plan_name for a35
SQL> select sql_handle, sql_text, plan_name, origin from dba_sql_plan_baselines where sql_text like 'select * from test2 where object_id=20%';

SQL_HANDLE               SQL_TEXT                                 PLAN_NAME                           ORIGIN
------------------------ ---------------------------------------- ----------------------------------- --------------
SQL_20df29fdb3e8ac52 select * from test2 where object_id=20 SQL_PLAN_21rt9zqtyjb2k60b1ef84 MANUAL-LOAD

对原始sql加hint,执行新的sql

SQL> select /*+ full(test2) */ * from test2 where object_id=20;

获得新sql语句的sql_id和plan_hash_value

SQL> select sql_id, plan_hash_value, sql_text from v$sqlarea where sql_text like 'select /*+ full(test2) */%';

SQL_ID               PLAN_HASH_VALUE SQL_TEXT
-------------------- --------------- ----------------------------------------
11cptg7m2vcwr 300966803 select /*+ full(test2) */ * from test2 w
here object_id=20

将新的sql_id和plan_hash_value加入到原始sql的基线中

SQL> var temp number;
SQL> begin
:temp := dbms_spm.load_plans_from_cursor_cache(sql_id=>'11cptg7m2vcwr', plan_hash_value=>300966803, sql_handle =>'SQL_20df29fdb3e8ac52');
end;
/

查看原始sql的基线

SQL> select sql_handle, sql_text, plan_name, origin from dba_sql_plan_baselines where sql_text like 'select * from test2 where object_id=20%';

SQL_HANDLE               SQL_TEXT                                 PLAN_NAME                           ORIGIN
------------------------ ---------------------------------------- ----------------------------------- --------------
SQL_20df29fdb3e8ac52 select * from test2 where object_id=20 SQL_PLAN_21rt9zqtyjb2k60b1ef84 MANUAL-LOAD
SQL_20df29fdb3e8ac52 select * from test2 where object_id=20 SQL_PLAN_21rt9zqtyjb2k99963deb MANUAL-LOAD

可以看到新的执行计划plan_name为SQL_PLAN_21rt9zqtyjb2k99963deb已经加到原始sql的基线中了

删除旧的sql_plan

SQL> var temp number;
SQL> begin
:temp := dbms_spm.drop_sql_plan_baseline(sql_handle =>'SQL_20df29fdb3e8ac52', plan_name=>'SQL_PLAN_21rt9zqtyjb2k60b1ef84');
end;
/

新开一个窗口,再运行原始sql语句

SQL> set autot trace
SQL> select * from test2 where object_id=20;

Execution Plan
----------------------------------------------------------
Plan hash value: 300966803 ---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 98 | 347 (1)| 00:00:05 |
|* 1 | TABLE ACCESS FULL| TEST2 | 1 | 98 | 347 (1)| 00:00:05 |
--------------------------------------------------------------------------- Note
-----
- SQL plan baseline "SQL_PLAN_21rt9zqtyjb2k99963deb" used for this statement

可以看到原始sql的执行计划已经改变了。

四、总结

spm只是一个临时应急解决方案,数据库出现执行计划不正确,应该从源头查找原因,比如说统计信息,索引是否失效等等。

Oracle - SPM固定执行计划(二)的更多相关文章

  1. Oracle - SPM固定执行计划

    1. 通过dbms_xplan.display_cursor查看指定sql都有哪些执行计划 SQL> select * from table(dbms_xplan.display_cursor( ...

  2. Oracle - SPM固定执行计划(一)

    一.前言 生产中偶尔会碰到一些sql,有多种执行计划,其中部分情况是统计信息过旧造成的,重新收集下统计信息就行了.但是有些时候重新收集统计信息也解决不了问题,而开发又在嗷嗷叫,没时间让你去慢慢分析原因 ...

  3. SQL Server如何固定执行计划

    SQL Server 其实从SQL Server 2005开始,也提供了类似ORACLE中固定执行计划的功能,只是好像很少人使用这个功能.当然在SQL Server中不叫"固定执行计划&qu ...

  4. Oracle 固定执行计划-使用SPM(Sql Plan Management)固定执行计划

    固定执行计划-使用SPM(Sql Plan Management)固定执行计划 转载自:http://www.lunar2013.com/2016/01/固定执行计划-使用spm%EF%BC%88sq ...

  5. 基于Oracle的SQL优化(崔华著)-整理笔记-第2章“Oracle里的执行计划”

    详细介绍了Oracle数据里与执行计划有关的各个方面的内容,包括执行计划的含义,加何查看执行计划,如何得到目标SQL真实的执行计划,如何查看执行计划的执行顺序,Oracle数据库里各种常见的执行计划的 ...

  6. 固定执行计划-SQL PROFILE手工绑定

    固定(稳定)执行计划 你的应用的功能时快时慢,变化比较大,功能的性能能够保持一种稳定的状态,ORACLE 固定执行计划,采用以下这几种方式 oracle 9i使用 Outline oracle 10g ...

  7. Oracle性能优化之Oracle里的执行计划

    一.执行计划 执行计划是目标SQL在oracle数据库中具体的执行步骤,oracle用来执行目标SQL语句的具体执行步骤的组合被称为执行计划. 二.如何查看oracle数据库的执行计划 oracle数 ...

  8. Oracle中获取执行计划的几种方法分析

    以下是对Oracle中获取执行计划的几种方法进行了详细的分析介绍,需要的朋友可以参考下     1. 预估执行计划 - Explain PlanExplain plan以SQL语句作为输入,得到这条S ...

  9. Oracle查看SQL执行计划的方式

    Oracle查看SQL执行计划的方式     获取Oracle sql执行计划并查看执行计划,是掌握和判断数据库性能的基本技巧.下面案例介绍了多种查看sql执行计划的方式:   基本有以下几种方式: ...

随机推荐

  1. 《Java基础知识》Java方法重载和重写

    重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变.即外壳不变,核心重写! 重写的好处在于子类可以根据需要,定义特定于自己的行为. 也就是说子类 ...

  2. LeetCode 11月第2周题目汇总

    开源地址:点击该链接 前言 最近比较忙,这周几乎没有刷题,只刷了6道题~ 题目汇总 0387_first_unique_character_in_a_string类似的题目比较多了,字符串中找出特别的 ...

  3. SpringCloud之Spring Cloud Stream:消息驱动

    Spring Cloud Stream 是一个构建消息驱动微服务的框架,该框架在Spring Boot的基础上整合了Spring Integrationg来连接消息代理中间件(RabbitMQ, Ka ...

  4. docker快速部署本地项目到服务器(tomcat8+mysql8)

    目标是:将本地运行的spring项目,部署到服务器上 为什么使用docker? 环境隔离 服务器上,各种环境交杂,使用docker,能清楚的把各个项目进行隔离,不单维护的人员方便,也会省去很多维护这些 ...

  5. Hadoop_简介_01

    1. Apache Hadoop 1.1 Hadoop介绍 Hadoop是Apache旗下的一个用java语言实现的开源软件框架, 是一个开发和运行处理大规模数据的软件平台. 允许使用简单的编程模型在 ...

  6. inux 内存监控分析

    一.free 查看系统总的内存情况 第一部分Mem行: total 内存总数: 3768M used 已经使用的内存数: 3136M free 空闲的内存数: 632M shared 当前已经废弃不用 ...

  7. 网页解析库-Xpath语法

    网页解析库 简介 除了正则表达式外,还有其他方便快捷的页面解析工具 如:lxml (xpath语法) bs4 pyquery等 Xpath 全称XML Path Language, 即XML路径语言, ...

  8. 搭建私人的云笔记_使用webdav服务

    搭建私人的云笔记_使用webdav服务 转载注明来源: 本文链接 来自osnosn的博客,写于 2019-10-10. 手机上有很多云笔记app,大多支持云存储.可是把笔记放在别人的服务器上,总觉得不 ...

  9. SpringCloud找不到@HystrixCommand标签

    版本声明: SpringCloud:Greenwich.SR4 SpringBoot:2.1.9.RELEASE 解决方案: 添加坐标 <dependency> <groupId&g ...

  10. mac环境 python3.7 lzma.py 报错解决

    import pandas as pd 在使用pandas时报Could not import the lzma module解决方法: 1.安装了 backports.lzma pip3 insta ...