首页 > 数据库 >oracle 为sql寻找更好的执行计划并绑定

oracle 为sql寻找更好的执行计划并绑定

时间:2023-04-18 10:38:51浏览次数:37  
标签:-- 绑定 value plan sql SQL oracle id


这种方法只适合sql本身有更好的执行计划,不能绑定自己构造的执行计划(比如加hint),并且每次只能针对一个sql_id,如果慢sql未使用绑定变量导致有很多类似sql最好从索引、sql改写等方面优化。

首先找到慢sql的sql_id,查看其各执行计划平均执行时间

-- 可用v$active_session_history,dba_hist_active_sess_history时间范围较长
select SQL_PLAN_HASH_VALUE,round(avg(RUN_MINS),2) as avg_run_mins,count(*) from
(
SELECT T.SQL_ID, T.SQL_EXEC_ID,
 CAST(MAX(T.SAMPLE_TIME) AS DATE) EXEC_END_TIME,
 T.SQL_EXEC_START EXEC_START_TIME,
 ROUND((CAST(MAX(T.SAMPLE_TIME) AS DATE) - T.SQL_EXEC_START) * 1440, 2) RUN_MINS,
 T.SQL_PLAN_HASH_VALUE, T.MODULE
 FROM dba_hist_active_sess_history T
 WHERE T.SQL_ID = '5w91hk4nmcmrx'
 AND T.SAMPLE_TIME > SYSDATE - 36
 GROUP BY T.SQL_ID, T.SQL_EXEC_ID, T.SQL_EXEC_START, T.SQL_PLAN_HASH_VALUE, T.MODULE
 ORDER BY EXEC_END_TIME DESC
 )
 group by SQL_PLAN_HASH_VALUE
 order by 2 desc;

oracle 为sql寻找更好的执行计划并绑定_执行计划

一、 从缓存中载入

查询所需执行计划是否在缓存中,如果在,直接从缓存载入更为简单

select sql_text,
 sql_id,
 hash_value,
 child_number,
 plan_hash_value,
 to_char(LAST_ACTIVE_TIME, 'hh24:mi:ss') time
 from v$sql a
where sql_id='26kqp5puukbh8' and plan_hash_value='3059001790';

oracle 为sql寻找更好的执行计划并绑定_执行计划_02

从库缓存中载入(时间太久可能已不在缓存中)

DECLARE
 l_plans_loaded PLS_INTEGER;
BEGIN
l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(sql_id => '5w91hk4nmcmrx',plan_hash_value=> '3570344087');
END;
/

查看载入后信息

SELECT * FROM dba_sql_plan_baselines where origin='MANUAL-LOAD' order by created desc;


oracle 为sql寻找更好的执行计划并绑定_sql_03


固定执行计划,将该基线转为fixed


DECLARE
 i NATURAL;
 BEGIN
 i := dbms_spm.alter_sql_plan_baseline(
 'SQL_3ebb770da822a759',
 'SQL_PLAN_3xfvr1qn259ut58e43372',
 attribute_name => 'FIXED',
 attribute_value => 'YES');
 dbms_output.put_line(i);
 END;
/


再次查看


SELECT * FROM dba_sql_plan_baselines where origin='MANUAL-LOAD' order by created desc;


oracle 为sql寻找更好的执行计划并绑定_执行计划_04


查看基线中的执行计划

select * from table(dbms_xplan.display_sql_plan_baseline('SQL_3ebb770da822a759', plan_name => 'SQL_PLAN_3xfvr1qn259ut58e43372',format => 'ADVANCED'));

删除方法如下

SELECT * FROM dba_sql_plan_baselines where origin='MANUAL-LOAD' order by created desc;

DECLARE
v_text PLS_INTEGER;
BEGIN
v_text := DBMS_SPM.drop_sql_plan_baseline(sql_handle => 'SYS_SQL_7b76323ad90440b9',plan_name => NULL);
DBMS_OUTPUT.put_line(v_text);
END;
/

二、 利用sqlset从AWR中载入

如果好的执行计划已不在缓存中,只能尝试从AWR中载入。这个方法保留的执行计划时间会比较长,当然也不是永久的,也有可能会查不到。

查看期望的执行计划产生的时间

select * from dba_hist_sql_plan where sql_id='26kqp5puukbh8' and plan_hash_value='3059001790' order by timestamp desc;
-- 2018/2/28 17:32:03

oracle 为sql寻找更好的执行计划并绑定_sql_05

根据产生时间找到对应的快照ID

select * from dba_hist_ash_snapshot d where d.BEGIN_INTERVAL_TIME like '28-FEB-18%' order by d.BEGIN_INTERVAL_TIME;
--24257和24258(看END_INTERVAL_TIME字段)

oracle 为sql寻找更好的执行计划并绑定_执行计划_06

查看数据库中已有dba_sqlset

select owner, name, id, created, statement_count from dba_sqlset order by created;

oracle 为sql寻找更好的执行计划并绑定_dba_07

创建sqlset

begin
DBMS_SQLTUNE.CREATE_SQLSET('mysts180104','SQL Tuning Set for loading plan into SQL Plan Baseline');
end;
/

指定快照号从awr中将执行计划load进sqlset

DECLARE
 cur sys_refcursor;
 BEGIN
 OPEN cur FOR 
 SELECT VALUE(P)
 FROM TABLE(
 dbms_sqltune.select_workload_repository
 (begin_snap=>24257, --老执行计划起始的snap id
 end_snap=>24258, --老执行计划结束的snap id
 basic_filter=>'sql_id = ''26kqp5puukbh8''', --老执行计划起始的sql id
 attribute_list=>'ALL')
 ) p;
 DBMS_SQLTUNE.LOAD_SQLSET( sqlset_name=> 'mysts180306', populate_cursor=>cur);
 CLOSE cur;
 END;
/

 load 完之后检查sqlset情况,发现已经存在(如果为空可以把snap范围加大一点)

SELECT first_load_time,executions as execs,parsing_schema_name,elapsed_time / 1000000 as elapsed_time_secs,cpu_time / 1000000 as cpu_time_secs,buffer_gets,disk_reads,direct_writes,rows_processed,fetches,optimizer_cost,sql_plan,plan_hash_value,sql_id,sql_text
FROM TABLE(DBMS_SQLTUNE.SELECT_SQLSET(sqlset_name => 'mysts180306'));

oracle 为sql寻找更好的执行计划并绑定_dba_08

查看sqlset中的执行计划

set long 999999999
set line 1000
set pages 1000
SELECT * FROM table (DBMS_XPLAN.DISPLAY_SQLSET('mysts180306','26kqp5puukbh8'));

-- 可以看到其中的Plan hash value值
Plan hash value: 1734317001
...
Plan hash value: 2335232284
...
Plan hash value: 3059001790  <-- 绑定的执行计划

从sqlset中载入基线

DECLARE
 my_plans pls_integer; 
 BEGIN
 my_plans := DBMS_SPM.LOAD_PLANS_FROM_SQLSET(
 sqlset_name => 'mysts180306',
 basic_filter=>'plan_hash_value = ''3059001790''');
 END;
/

检查创建后信息

SELECT * FROM dba_sql_plan_baselines where origin='MANUAL-LOAD' order by created desc;

oracle 为sql寻找更好的执行计划并绑定_SQL_09

将该基线转为fixed

DECLARE
 i NATURAL;
 BEGIN
 i:=dbms_spm.alter_sql_plan_baseline(
 'SQL_3ebb770da822a759',
 'SQL_PLAN_3xfvr1qn259ut58e43372',
 attribute_name => 'FIXED',
 attribute_value => 'YES');
 dbms_output.put_line(i);
 END;
/

查看固定后信息

SELECT * FROM dba_sql_plan_baselines where origin='MANUAL-LOAD' order by created desc;

oracle 为sql寻找更好的执行计划并绑定_执行计划_10

查看基线中的执行计划

select * from table(dbms_xplan.display_sql_plan_baseline('SQL_3ebb770da822a759', plan_name => 'SQL_PLAN_3xfvr1qn259ut58e43372',format => 'ADVANCED'));
-- 可以看到
-- Plan name: SQL_PLAN_3xfvr1qn259ut58e43372 Plan id: 1491350386
-- Enabled: YES Fixed: YES Accepted: YES Origin: MANUAL-LOAD

三、 将指定sql执行计划清出缓存

如果awr中都没有好的执行计划信息了,可以赌一把把当前缓存sql_id的执行计划清出去,让它重新解析看看能不能生成回正确的执行计划。如果是参数嗅探导致的执行计划改变问题,这样有可能是可以的。

col SQL_TEXT format a35
col ADDRESS format a18
col HASH_VALUE format a10
select s.SQL_TEXT, s.ADDRESS, s.HASH_VALUE||'' from v$sqlarea s where sql_text like 'select /*gg*/count(*) from test%';

SQL_TEXT                             ADDRESS           S.HASH_VALUE||''
----------------------------------- ------------------ --------------------------------
select /*gg*/count(*) from test     0000000300B06D70   728448230

--清除该sql执行计划
exec sys.dbms_shared_pool.purge('0000000300B06D70,728448230','c');

-- 再次查询,一般无输出结果,除非sql执行频率特别高
select s.SQL_TEXT, s.ADDRESS, s.HASH_VALUE||'' from v$sqlarea s where sql_text like 'select /*gg*/count(*) from test%';

标签:--,绑定,value,plan,sql,SQL,oracle,id
From: https://blog.51cto.com/u_13631369/6202536

相关文章

  • sqlserver 数据库状态转换图
    今天发现一个很好的图,非常清晰的展示了sqlserver的各种状态及切换原因/方法。简单介绍一下各种状态:ONLINE(在线):数据库正常运行。只有数据库成功恢复后会进入这个状态,也只有这种状态数据库是正常可用的。RESTORING(正在还原):正在执行数据库还原。如果还原时使用NORECOVERY模式,数据库会......
  • Oracle授予普通用户kill session权限
    开发A在测试环境操作时有时会遇到阻塞问题,需要找DBA帮忙查看阻塞会话及killsession,后来觉得太麻烦想要个kill会话的权限,查了下Oracle授予普通用户killsession权限的方法。1.授予altersystem权限官方文档查到,killsession需要ALTERSYSTEM权限,但是这个权限非常大,不能直接给GRANT......
  • pg 如何生成创建表sql语句?
    oracle有dbms_metadata.get_ddl;sqlserver可以直接右键;mysql有showcreatetable但pg好像没有直接的方法,网上找到了几种自己创建函数的方法,收集一下。法一:支持生成包含:字段(支持数组类型字段)、约束、索引(支持唯一索引、全类型索引)在内的建表语句。CREATEORREPLACEFUNCTION"public......
  • kettle工具如何使用service_name连接oracle
    开发反馈使用kettle工具连pdb连不上,报错如下: Causedby:org.pentaho.di.core.exception.KettleDatabaseException:Errorconnectingtodatabase:(usingclassoracle.jdbc.driver.OracleDriver)Listenerrefusedtheconnectionwiththefollowingerror:ORA-12505,TNS:l......
  • Oracle 恢复之using backup controlfile 和 until cancel
    Oracle恢复数据库时有几个常用但非常相似的命令,整理下它们各自的作用及适用场景。recoverdatabaserecoverdatabaseuntilcancelrecoverdatabaseusingbackupcontrolfilerecoverdatabaseusingbackupcontrolfileuntilcancelrecoverdatabaseuntilcancelusingbackupc......
  • Oracle 利用在线重定义进行分区表转换
    例如原始非分区表为createtableTESTUSER.LOG_TEST("id"CHAR(36)primarykey,"created_at"DATE)一、选择重定义方法   Bykey,选择主键或者所有字段有NOTNULL约束的唯一键用于在线重定义操作。使用这种方法,在线重定义之前和之后表应该有相同的主键字段(默......
  • PLSQL 多个连接
    PLSQL多个连接文件地址D:\app\think\product\11.2.0\instantclient_11_2\network\admin\tnsnames.ora#tnsnames.oraNetworkConfigurationFile:D:\app\think\product\11.2.0\client_1\NETWORK\ADMIN\tnsnames.ora#GeneratedbyOracleconfigurationtools.......
  • Oracle Dataguard安装先决条件与注意事项
    业务方要求把一个单实例DB做成dg,由于之前是业务方自己安装管理的,过去检查一番,发现这个库软件居然不是企业版的。整理了几篇相关的官方文档链接给业务方,反馈Oracle标准版不支持dg。顺便也根据官方文档(19c)整理一份checklist,方便以后使用。一、硬件与OS要求1.主库与所有从库安装版本......
  • oracle、达梦数据库、MySQL数据创建表与字段注释
    /**1.oracle注释*//*表本身注释*/commentontable表名is'注释信息';/*字段注释*/commentoncolumn表名.字段名is'注释信息';/*实例如下:*/commentontableUSERis'用户表';commentoncolumnUSER.IDis'主键ID';/**2.MySQL注释*//*表本身注释*/altertable表名co......
  • Oracle等待事件(二)—— free buffer wait 常见原因及对应解决方法
    首先看看官方文档中的描述Thiswaiteventindicatesthataserverprocesswasunabletofindafreebufferandhaspostedthedatabasewritertomakefreebuffersbywritingoutdirtybuffers.Adirtybufferisabufferwhosecontentshavebeenmodified.Dirtyb......