SQL:执行计划的几种方法

时间:2021-09-26 04:27:53
查看sql执行计划方法
1.set autotrace (需要执行sql)
2.explain plan for
3.dbms_xplan.display_cursor
4.dbms_xplan.display_awr
5.查看SQL语句执行计划的个数
6.sql_trace
7.10046
8.oradebug
9.删除执行计划:



---------------------------------------------------------
查看Oracle执行计划的几种方法

一、autotrace  --都要执行sql
   set autotrace on
   select * from dual;
   set autotrace traceonly  --不显示输出结果


二、explain plan for
    EXPLAIN PLAN FOR   select * from tableA where paraA=1;
    select * from table(DBMS_XPLAN.DISPLAY) ;
 或者
    EXPLAIN PLAN FOR   select * from tableA where paraA=1;
    @?/rdbms/admin/utlxpls.sql
 
 
  SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'+ALLSTATS'));
 
  set verify off                                                                                          
  select s.sid,s.serial#,s.sql_id,s.username from v$session s,v$process p where s.paddr=p.addr and p.spid='&spid';
   
   
  select SID,SERIAL#,SQL_ID,sql_child_number,status,last_call_et from v$session where sql_id='&sqlid';
 
         SID    SERIAL# SQL_ID                     SQL_CHILD_NUMBER STATUS           LAST_CALL_ET
  ---------- ---------- -------------------------- ---------------- ---------------- ------------
         200         65 14rxtm6jhddh0                             0 ACTIVE                    297
 
从内存中获取当前会话SQL语句的执行计划      
   set verify off
   select * from table(dbms_xplan.display_cursor('&sqlid',&sql_child_number,'last'));   
   
直接从AWR中获取SQL语句执行计划   
   set verify off
   select * from table(dbms_xplan.display_awr('&sqlid'));

查看通过AWR的查看SQL语句执行计划的变化  
   set verify off  
   col begin_interval_time for a35
   select a.instance_number,a.snap_id,a.sql_id,a.plan_hash_value,b.begin_interval_time
   from dba_hist_sqlstat a,dba_hist_snapshot b
   where a.snap_id=b.snap_id
   and a.sql_id='&sqlid'
   order by a.instance_number,b.begin_interval_time desc;
   
查看SQL语句执行计划的个数
  select sql_id,hash_value,child_number,plan_hash_value from v$sql_plan where sql_id='&sqlid';   
  select * from table(dbms_xplan.display_cursor('&sqlid',&sql_child_number,'last'));

三、sql_trace
   alter session set SQL_TRACE=true;
   SQL> alter session set SQL_TRACE=true;
   寻找路径方法如下:
      方法1: alter session set tracefile_identifier=test;
      方法2: select * from v$diag_info where name like 'Default%'
   SQL> select * from dual;
   SQL> alter session set SQL_TRACE=false;
   
   开启跟踪:SQL> exec dbms_system.set_SQL_TRACE_in_session(127,31923,true);
   关闭跟踪:SQL> exec dbms_system.set_SQL_TRACE_in_session(127,31923,false);
   
   select spid from v$process where addr in ( select paddr from v$session where sid=127 ) ;
   
   cd  /u01/app/oracle/diag/rdbms/r5/r5/trace
   ll *30180*
   tkprof r5_ora_30180.trc a.txt
   vi a.txt
   
四、10046
  开启:SQL> alter session set events '10046 trace name context forever, level 8';
  关闭:SQL> alter session set events '10046 trace name context off';
  对其他用户进行设置:
  SQL> select sid,serial#,username from v$session where username='XXX';
       SID    SERIAL# USERNAME
    ------ ---------- ------------------
       127      31923 A
  SQL> exec dbms_system.set_ev(127,31923,10046,8,'A');
    --使用一下SQL找到当前session的跟踪文件:
  SELECT d.value|| '/' ||lower(rtrim(i.instance, chr( 0 )))|| '_ora_' ||p.spid|| '.trc' trace_file_name
    from
    ( select p.spid
       from v$mystat m
            ,v$session s
            , v$process p
       where m.statistic# = 1
         and s.sid = m.sid
         and p.addr = s.paddr) p,
    ( select t.instance
        from v$thread t
            ,v$parameter v
       where v.name = 'thread'
         and (v.value = 0 or t.thread# = to_number(v.value))) i,
    ( select value
         from v$parameter
        where name = 'user_dump_dest' ) d;

--其它用户的 session:
    SELECT d.value|| '/' ||lower(rtrim(i.instance, chr( 0 )))|| '_ora_' ||p.spid|| '.trc'trace_file_name
    from
    ( select p.spid
        from v$session s
            ,v$process p
       where s.sid= '27'
         and s. SERIAL#= '30'
         and p.addr = s.paddr) p,
    ( select t.instance
        from v$thread t
        ,v$parameter v
      where v.name = 'thread'
        and (v.value = 0 or t.thread# = to_number(v.value))
     ) i,
     ( select value
         from v$parameter
        where name = 'user_dump_dest' ) d;
 

五、oradebug
 SQL> select p.PID,p.SPID,s.SID from v$process p,v$session s where s.paddr = p.addr and s.sid = 421;
 
       PID SPID                SID
---------- ------------ ----------
        28 241816              421
 
SQL> oradebug setospid 241816
Oracle pid: 28, Unix process pid: 241816, image: oracle@p690ca
 
SQL> oradebug unlimit
已处理的语句
 
SQL> oradebug event 10046 trace name context forever,level 12
已处理的语句
 oradebug tracefile_name
 /u01/app/oracle/admin/ipratest/udump/ipratest_ora_241816.trc
 oradebug event 10046 trace name context off


1> oradebug有哪些可用命令?
   以sysdba身份登陆数据库,通过oradebug help可以看到oradebug常用命令
   sqlplus / as sysdba
   oradebug help
2> 跟踪当前会话信息
   oradebug setmypid  --跟踪当前会话
   oradebug setospid  --跟踪系统进程
   oradebug setorapid  --跟踪ORACLE进程
   oradebug unlimit   --取消trace文件大小限制     
   oradebug tracefile_name  --查看trace文件名及位置
3> 用oradebug做session级10046或10053
   oradebug setmypid
   oradebug unlimit
   oradebug session_event 10046 trace name context forever ,level 4 --启用会话级10046
   oradebug event 10046 trace name context off   --关闭10046事件
   oradebug tracefile_name  --查看tracefile文件位置及文件名
4> 用oradebug做oracle process级10046
   oradebug setorapid
   oradebug unlimit
   oradebug event 10046 trace name context forever ,level 4
   oradebug event 10046 trace name context off
   oradebug tracefile_name
5> oradebug系统hang住原因分析
   如果系统HANG住,只要sys用户可以登陆,那么用oradebug做原因分析是非常有用的
   oradebug setmypid
   oradebug unlimit
   oradebug setinst all   --RAC环境
   oradebug hanganalyze 3  -- 级别一般指定为3足够了
   oradebug -g def dump systemstate 10  --RAC环境
   oradebug tracefile_name
6> 获取某进程的状态信息
   oradebug setospid 22180
   oradebug dump processstate 10
   oradebug tracefile_name
7> 获取进程错误信息状态
   oradebug setospid 22180
   oradebug dump errorstack 3
8> 追踪造成错误信息的原因,如ORA-04031
   oradebug event 4031 trace name errorstack level 3
这些是常用到的一些命令,更多信息参考DAVE博客,他介绍的比较详解
    http://blog.csdn.net/tianlesoftware/article/details/6525628




















 第一步:
     EXPLAIN PLAN FOR   select * from tableA where paraA=1
 第二步:   
    select * from table(DBMS_XPLAN.DISPLAY) ;

1.  
     SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'+ALLSTATS'));
2.
     select    /*+ gather_plan_statistics */ count(*) from aa
3.   
     SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'+ALLSTATS'));



2.用explain plan命令
    sqlplus > explain plan for select * from testdb.myuser
    sqlplus > select * from table(dbms_xplan.display);

3、启用SQL_TRACE跟踪所有后台进程活动:
    SQL> alter session set SQL_TRACE=true;
    方法1:  alter session set tracefile_identifier=test;
    方法2: select * from v$diag_info where name like 'Default%'

    开启跟踪:SQL> exec dbms_system.set_SQL_TRACE_in_session(127,31923,true);
    关闭跟踪:SQL> exec dbms_system.set_SQL_TRACE_in_session(127,31923,false);
    然后使用oracle自带的tkprof命令行工具格式化跟踪文件。
/*
     select a.username ,a.sid,a.serial#,a.status,b.pid,b.spid from v$session a ,v$process b where a.paddr=b.addr
*/
SQL> select spid from v$process where addr in ( select paddr from v$session where sid=127 ) ;
SPID
------------------------
30180
[oracle@nubia ~]$ cd  /u01/app/oracle/diag/rdbms/r5/r5/trace
[oracle@nubia trace]$ ll *30180*
-rw-r----- 1 oracle oinstall 1005655 03-30 16:14 r5_ora_30180.trc
-rw-r----- 1 oracle oinstall 2470 03-30 16:14 r5_ora_30180.trm
[oracle@nubia trace]$ tkprof r5_ora_30180.trc a.txt
TKPROF: Release 11.2.0.2.0 - Development on Mon Mar 30 16:35:19 2015
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
[oracle@nubia trace]$ vi a.txt

4、使用10046事件进行查询:
    10046事件级别:
    Lv1  - 启用标准的SQL_TRACE功能,等价于SQL_TRACE
    Lv4  - Level 1 + 绑定值(bind values)
    Lv8  - Level 1 + 等待事件跟踪
    Lv12 - Level 1 + Level 4 + Level 8
    全局设定:
    OracleHome/admin/SID/pfile中指定: EVENT="10046 trace name context forever,level 12"
    当前session设定:
    开启:SQL> alter session set events '10046 trace name context forever, level 8';
    关闭:SQL> alter session set events '10046 trace name context off';
    对其他用户进行设置:
    SQL> select sid,serial#,username from v$session where username='XXX';
       SID    SERIAL# USERNAME
    ------ ---------- ------------------
       127      31923 A
    SQL> exec dbms_system.set_ev(127,31923,10046,8,'A');
5、使用tkprof格式化跟踪文件: (根据下面SQL语句得到的文件都不存在该目录下,郁闷啊,懵懂啊...)
一般,一次跟踪可以分为以下几步:
1、界定需要跟踪的目标范围,并使用适当的命令启用所需跟踪。
2、经过一段时间后,停止跟踪。此时应该产生了一个跟踪结果文件。
3、找到跟踪文件,并对其进行格式化,然后阅读或分析。

--使用一下SQL找到当前session的跟踪文件:
SELECT d.value|| '/' ||lower(rtrim(i.instance, chr( 0 )))|| '_ora_' ||p.spid|| '.trc' trace_file_name
from
( select p.spid from v$mystat m,v$session s, v$process p
where m.statistic# = 1 and s.sid = m.sid and p.addr = s.paddr) p,
( select t.instance from v$thread t,v$parameter v
where v.name = 'thread' and (v.value = 0 or t.thread# = to_number(v.value))) i,
( select value from v$parameter where name = 'user_dump_dest' ) d;

--其它用户的 session:
    SELECT d.value|| '/' ||lower(rtrim(i.instance, chr( 0 )))|| '_ora_' ||p.spid|| '.trc'trace_file_name
    from
    ( select p.spid from v$session s, v$process p
          where s.sid= '27' and s. SERIAL#= '30' and p.addr = s.paddr) p,
    ( select t.instance from v$thread t,v$parameter v
          where v.name = 'thread' and (v.value = 0 or t.thread# = to_number(v.value))) i,
    ( select value from v$parameter where name = 'user_dump_dest' ) d;
 
--查找后使用tkprof命令,将TRACE文件格式为到D盘的explain_format.txt文件中
SQL> $tkprof d:/oracle/admin/FZLGFM/udump/fzlgfm_ora_3468.trc  d:/explain_format.txt
文件内容大致如下(看不太懂....懵懂啊.....天啊....神啊.....过几时就懂了/////////////)
TKPROF: Release 9.2.0.1.0 - Production on 星期二 4月 20 13:59:20 2010
Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
Trace file: d:/oracle/admin/FZLGFM/udump/fzlgfm_ora_3468.trc
Sort options: default
********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************
alter session set events '10046 trace name context forever, level 8'
 
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        1      0.00       0.00          0          0          0           0
 
Misses in library cache during parse: 0
Misses in library cache during execute: 1
Optimizer goal: CHOOSE
Parsing user id: SYS





sql_profle内容:
SELECT so.signature,extractValue(value(h),'.') AS hint
    FROM sys.sqlobj$data od, sys.sqlobj$ so,
    table(xmlsequence(extract(xmltype(od.comp_data),'/outline_data/hint'))) h
    WHERE so.name = 'SYS_SQLPROF_01436cac2c3c0000'
    AND so.signature = od.signature
    AND so.category = od.category
    AND so.obj_type = od.obj_type
   AND so.plan_id = od.plan_id
 
 

 alter system flush shared_pool;
删除执行计划:
在11g中,Oracle的DBMS_SHARED_POOL包新增了PURGE功能
select count(*) from dual;
select count(*) from v$sqlarea;
select sql_id, address, hash_value, executions, loads, parse_calls, invalidations ,sql_text from v$sqlarea  where sql_text like '%select count(*) from dual%';

select sql_id, address, hash_value, executions, loads, parse_calls, invalidations  from v$sqlarea  where lower(sql_text) like '%dual%';
 
 
 
alter system flush shared_pool;

select count(*) from dual;
COUNT(*)
----------
1
 
select sql_id, address, hash_value, executions, loads, parse_calls, invalidations ,sql_text from v$sqlarea  where sql_text like '%select count(*) from dual%';
 
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
4m94ckmu16f9k 00000000B6C61FC0 4094900530 1 2 1 1
SQL> select 1 from dual;
1
----------
1
 
SQL> select * from dual;
D
-
X
 
select sql_id, address, hash_value, executions, loads, parse_calls, invalidations   from v$sqlarea  www.2cto.com    where lower(sql_text) like '%dual%';
SQL_ID         ADDRESS        HASH_VALUE  EXECUTIONS  LOADS      PARSE_CALLS   INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
gr7s3j0cg8pr6 00000000B6A5A470 418666214  3           1          3            0
520mkxqpf15q8 00000000B6DD9610 2866845384 1           2          1            1
ak90gdq0udv37 00000000B6E3C6B0 2175200359 3           2          3            1
4m94ckmu16f9k 00000000B6C61FC0 4094900530 1           2          1            1
a5ks9fhw2v9s1 00000000B698DA88 942515969  1           2          1            1
 
exec dbms_shared_pool.purge('00000000B6C61FC0,4094900530', 'c')
PL/SQL procedure successfully completed.
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations  from v$sqlarea   where lower(sql_text) like '%dual%';
SQL_ID         ADDRESS          HASH_VALUE  EXECUTIONS  LOADS      PARSE_CALLS  INVALIDATIONS
------------- ---------------- ----------   ---------- ---------- ----------- -------------
gr7s3j0cg8pr6 00000000B6A5A470 418666214     4         1           4            0
520mkxqpf15q8 00000000B6DD9610 2866845384    1         2           1            1
ak90gdq0udv37 00000000B6E3C6B0 2175200359    3         2           3            1
a5ks9fhw2v9s1 00000000B698DA88 942515969     1         2           1            1
 
过程PURGE的第一个参数为V$SQLAREA中用逗号分隔的ADDRESS列和HASH_VALUE列的值,第二个参数’c’表示PURGE的对象是CURSOR,不过实际上这里可以使用除了P(PROCEDURE/FUNCTION/PACKAGE)、T(TYPE)、R(TRIGGER)和Q(SEQUENCE)的任何值  www.2cto.com  
使用这种方法,就可以精确的将一个SQL从共享池中删除,从而使得Oracle为这个SQL重新生成执行计划。这种方法只针对单个SQL语句,使得解决问题的同时不会造成任何的误伤。
不过需要注意一点,在10.2.0.4中,虽然PURGE过程已经存在,但是要使这个过程可以真正的生效,还必须设置一个EVENT:
SQL> alter system set event = '5614566 trace name context forever' scope = spfile;
System altered.
设置EVENT后需要重启,DBMS_SHARED_POOL的PURGE才可以生效。也就是说,除非提前进行过设置,否则这个PURGE的功能对于一个产品环境而言,必须在10.2.0.5以上版本才可以使用。