|
# ######################################################################################################################################## |
|
# Retrieve the SQLTEXT + BIND VARIABLES + EXEC PLAN + PLAN HISTORY + BASELINE + FIX PLAN + TUNING ADVISOR |
|
VER="[3.6]" |
|
# # # # |
|
# Authors: Mahmmoud ADEL # # # # # # |
|
# Farrukh Salman # # # #### |
|
# Created: 24-12-11 # # # # # |
|
# Modified: 31-12-13 Customized the script to run on various environments. |
|
# 06-05-14 Getting the Bind Variable info for the SQLID |
|
# 05-11-15 Fix Divided by Zero error |
|
# 16-06-16 Added SQL Tuning Option |
|
# 26-02-17 Added Execution History quoted from sqlhistory.sql written by: Tim Gorman (Evergreen Database Technologies, Inc.) |
|
# 14-11-17 Added a check for available tuning tasks |
|
# 26-07-18 Enhanced the display of Execution Plan |
|
# 11-09-18 Display SQL Advisor recommendation for the statement if it was already been vetted by SQL Advisor. |
|
# 28-08-19 Added Post Tuning note for hard parsing enforcement command. |
|
# 10-06-20 Adjust page formatting. |
|
# 02-07-20 Added Execution Plan History. |
|
# 05-10-20 Added SQL PLAN BASELINE Details. |
|
# 06-10-20 Added the feature of fixing an EXECUTION PLAN by creating a new BASELINE. |
|
# 06-10-20 Added the feature of fixing an EXECUTION PLAN from an EXIST BASELINE [if found]. |
|
# 11-10-20 Added a hint to help the user display the complete execution plan for a plan inside the BASELINE. |
|
# 13-02-21 Search the Execution Plans in AWR if the SQLID is not loaded in Cursor Cache. |
|
# 15-02-21 Show Drop Baseline SQL command for the user. |
|
# 19-09-21 Add the option of manually adding a plan to the SQL PLAN BASELINE using plan HASH VALUE. |
|
# 19-09-21 Control the SQLID displayed statistics history in days using HIST_DAYS variable. |
|
# 13-07-22 Setting SQLPLUS WRAP to ON to show the complete SQL statement. |
|
# ######################################################################################################################################## |
|
|
|
# ########### |
|
# Description: |
|
# ########### |
|
echo |
|
echo "=====================================================================================================" |
|
echo "This script display SQLTEXT, BIND VARIABLES, EXEC PLAN, BASELINE, FIX PLAN, SQL TUNING of a SQLID ..." |
|
echo "=====================================================================================================" |
|
echo |
|
|
|
ORACLE_OWNER_VFY="N" |
|
SKIPDBS="ASM\|MGMTDB|APX" |
|
|
|
HIST_DAYS=10 # Define how many DAYs back the script will dig for SQLID statistics. |
|
|
|
# ####################################### |
|
# Excluded INSTANCES: |
|
# ####################################### |
|
# Here you can mention the instances the script will IGNORE and will NOT run against: |
|
# Use pipe "|" as a separator between each instance name. |
|
# e.g. Excluding: -MGMTDB, ASM instances: |
|
|
|
EXL_DB="\-MGMTDB|ASM|APX" #Excluded INSTANCES [Will not get reported offline]. |
|
|
|
# ########################### |
|
# Listing Available Databases: |
|
# ########################### |
|
|
|
# Count Instance Numbers: |
|
INS_COUNT=$( ps -ef|grep pmon|grep -v grep|egrep -v ${EXL_DB}|wc -l ) |
|
|
|
# Exit if No DBs are running: |
|
if [ $INS_COUNT -eq 0 ] |
|
then |
|
echo "No Database is Running !" |
|
echo |
|
return |
|
fi |
|
|
|
# If there is ONLY one DB set it as default without prompt for selection: |
|
if [ $INS_COUNT -eq 1 ] |
|
then |
|
export ORACLE_SID=$( ps -ef|grep pmon|grep -v grep|egrep -v ${EXL_DB}|awk '{print $NF}'|sed -e 's/ora_pmon_//g'|grep -v sed|grep -v "s///g" ) |
|
|
|
# If there is more than one DB ASK the user to select: |
|
elif [ $INS_COUNT -gt 1 ] |
|
then |
|
echo |
|
echo "Select the ORACLE_SID:[Enter the number]" |
|
echo "---------------------" |
|
select DB_ID in $( ps -ef|grep pmon|grep -v grep|egrep -v ${EXL_DB}|awk '{print $NF}'|sed -e 's/ora_pmon_//g'|grep -v sed|grep -v "s///g" ) |
|
do |
|
integ='^[0-9]+$' |
|
if ! [[ ${REPLY} =~ ${integ} ]] || [ ${REPLY} -gt ${INS_COUNT} ] || [ ${REPLY} -eq 0 ] |
|
then |
|
echo |
|
echo "Error: Not a valid number!" |
|
echo |
|
echo "Enter a valid NUMBER from the displayed list !: i.e. Enter a number from [1 to ${INS_COUNT}]" |
|
echo "----------------------------------------------" |
|
else |
|
export ORACLE_SID=$DB_ID |
|
echo |
|
printf "`echo "Selected Instance: ["` `echo -e "\033[33;5m${DB_ID}\033[0m"` `echo "]"`\n" |
|
echo |
|
break |
|
fi |
|
done |
|
|
|
fi |
|
# Exit if the user selected a Non Listed Number: |
|
if [ -z "${ORACLE_SID}" ] |
|
then |
|
echo "You've Entered An INVALID ORACLE_SID" |
|
exit |
|
fi |
|
|
|
|
|
# ######################### |
|
# Getting ORACLE_HOME |
|
# ######################### |
|
ORA_USER=`ps -ef|grep ${ORACLE_SID}|grep pmon|grep -v grep|egrep -v ${EXL_DB}|grep -v "\-MGMTDB"|awk '{print $1}'|tail -1` |
|
USR_ORA_HOME=`grep -i "^${ORA_USER}:" /etc/passwd| cut -f6 -d ':'|tail -1` |
|
|
|
# SETTING ORATAB: |
|
if [ -f /etc/oratab ] |
|
then |
|
ORATAB=/etc/oratab |
|
export ORATAB |
|
## If OS is Solaris: |
|
elif [ -f /var/opt/oracle/oratab ] |
|
then |
|
ORATAB=/var/opt/oracle/oratab |
|
export ORATAB |
|
fi |
|
|
|
# ATTEMPT1: Get ORACLE_HOME using pwdx command: |
|
export PGREP=`which pgrep` |
|
export PWDX=`which pwdx` |
|
if [[ -x ${PGREP} ]] && [[ -x ${PWDX} ]] |
|
then |
|
PMON_PID=`pgrep -lf _pmon_${ORACLE_SID}|awk '{print $1}'` |
|
export PMON_PID |
|
ORACLE_HOME=`pwdx ${PMON_PID} 2>/dev/null|awk '{print $NF}'|sed -e 's/\/dbs//g'` |
|
export ORACLE_HOME |
|
fi |
|
|
|
# ATTEMPT2: If ORACLE_HOME not found get it from oratab file: |
|
if [ ! -f ${ORACLE_HOME}/bin/sqlplus ] |
|
then |
|
## If OS is Linux: |
|
if [ -f /etc/oratab ] |
|
then |
|
ORATAB=/etc/oratab |
|
ORACLE_HOME=`grep -v '^\#' ${ORATAB} | grep -v '^$'| grep -i "^${ORACLE_SID}:" | perl -lpe'$_ = reverse' | cut -f3 | perl -lpe'$_ = reverse' |cut -f2 -d':'` |
|
export ORACLE_HOME |
|
|
|
## If OS is Solaris: |
|
elif [ -f /var/opt/oracle/oratab ] |
|
then |
|
ORATAB=/var/opt/oracle/oratab |
|
ORACLE_HOME=`grep -v '^\#' ${ORATAB} | grep -v '^$'| grep -i "^${ORACLE_SID}:" | perl -lpe'$_ = reverse' | cut -f3 | perl -lpe'$_ = reverse' |cut -f2 -d':'` |
|
export ORACLE_HOME |
|
fi |
|
fi |
|
|
|
# ATTEMPT3: If ORACLE_HOME is in /etc/oratab, use dbhome command: |
|
if [ ! -f ${ORACLE_HOME}/bin/sqlplus ] |
|
then |
|
ORACLE_HOME=`dbhome "${ORACLE_SID}"` |
|
export ORACLE_HOME |
|
fi |
|
|
|
# ATTEMPT4: If ORACLE_HOME is still not found, search for the environment variable: [Less accurate] |
|
if [ ! -f ${ORACLE_HOME}/bin/sqlplus ] |
|
then |
|
ORACLE_HOME=`env|grep -i ORACLE_HOME|sed -e 's/ORACLE_HOME=//g'` |
|
export ORACLE_HOME |
|
fi |
|
|
|
# ATTEMPT5: If ORACLE_HOME is not found in the environment search user's profile: [Less accurate] |
|
if [ ! -f ${ORACLE_HOME}/bin/sqlplus ] |
|
then |
|
ORACLE_HOME=`grep -h 'ORACLE_HOME=\/' ${USR_ORA_HOME}/.bash_profile ${USR_ORA_HOME}/.*profile | perl -lpe'$_ = reverse' |cut -f1 -d'=' | perl -lpe'$_ = reverse'|tail -1` |
|
export ORACLE_HOME |
|
fi |
|
|
|
# ATTEMPT6: If ORACLE_HOME is still not found, search for orapipe: [Least accurate] |
|
if [ ! -f ${ORACLE_HOME}/bin/sqlplus ] |
|
then |
|
if [ -f /usr/bin/locate ] |
|
then |
|
ORACLE_HOME=`locate -i orapipe|head -1|sed -e 's/\/bin\/orapipe//g'` |
|
export ORACLE_HOME |
|
fi |
|
fi |
|
|
|
export LD_LIBRARY_PATH=${ORACLE_HOME}/lib |
|
|
|
|
|
# ######################################## |
|
# Exit if the user is not the Oracle Owner: |
|
# ######################################## |
|
case ${ORACLE_OWNER_VFY} in |
|
"Y") |
|
CURR_USER=`whoami` |
|
if [ ${ORA_USER} != ${CURR_USER} ]; then |
|
echo "" |
|
echo "You're Running This Sctipt with User: \"${CURR_USER}\" !!!" |
|
echo "Please Run This Script With The Right OS User: \"${ORA_USER}\"" |
|
echo "Script Terminated!" |
|
exit |
|
fi;; |
|
esac |
|
|
|
# ######################################## |
|
# SQLPLUS: Check SQL FULLTEXT & EXEC PLAN: |
|
# ######################################## |
|
# Variables |
|
echo |
|
echo "Enter the SQL_ID:" |
|
echo "================" |
|
while read SQLID |
|
do |
|
|
|
VAL1=$(${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set feedback off |
|
SELECT COUNT(*) FROM V\$SQL WHERE SQL_ID='${SQLID}'; |
|
EOF |
|
) |
|
VAL2=`echo ${VAL1}| awk '{print $NF}'` |
|
|
|
if [ ${VAL2} -gt 0 ] |
|
then |
|
|
|
${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set feedback off |
|
set linesize 156 pages 50000 long 2000000000 |
|
col SQL_FULLTEXT for a140 |
|
|
|
PROMPT |
|
PROMPT ************************* |
|
PROMPT Statement Info: [Per Execution | in Seconds] |
|
PROMPT ************************* |
|
SET LONG 999999999 PAGESIZE 10000 LINESIZE 200 |
|
col "ELAPSED|CPU TIME" for a16 |
|
col "PLSQL|JAVA TIME" for a24 |
|
col "APP|USR_IO|CLS WAIT" for a19 |
|
col "BUF_GET|DISK_R|DIRECT_W" for a23 |
|
col P_MEM_MB for 99999999 |
|
col "ROWS" for 999999999 |
|
col MODULE for a15 |
|
col FIRST_LOAD_TIME for a19 |
|
col LAST_LOAD_TIME for a19 |
|
col sql_plan_baseline for a30 |
|
col plan_hash_value for 999999999999999 |
|
col signature for 99999999999999999999 |
|
col SQL_PROFILE for a35 |
|
VARIABLE A REFCURSOR; |
|
DECLARE |
|
l_cursor SYS_REFCURSOR; |
|
BEGIN |
|
|
|
open :A for |
|
|
|
select executions EXEC,round(ELAPSED_TIME /1000000/(case when executions=0 then 1 else executions end),2) ||' | '|| round(CPU_TIME /1000000/(case when executions=0 then 1 else executions end),2) "ELAPSED|CPU TIME", |
|
--round(d.ELAPSED_TIME /1000000/(case when executions=0 then 1 else executions end),2) ELAPSED_TIME, |
|
round(APPLICATION_WAIT_TIME /1000000/(case when executions=0 then 1 else executions end),2) ||' | '|| round(USER_IO_WAIT_TIME /1000000/(case when executions=0 then 1 else executions end),2) ||' | '|| round(CLUSTER_WAIT_TIME /1000000/(case when executions=0 then 1 else executions end),2) "APP|USR_IO|CLS WAIT", |
|
--round(PLSQL_EXEC_TIME /1000000/(case when executions=0 then 1 else executions end),2)||' | '||round(JAVA_EXEC_TIME/1000000/(case when executions=0 then 1 else executions end),2) "PLSQL|JAVA TIME", |
|
round(ROWS_PROCESSED /(case when executions=0 then 1 else executions end),1)"ROWS", |
|
round(BUFFER_GETS /(case when executions=0 then 1 else executions end),2) ||' | '|| round(DISK_READS /(case when executions=0 then 1 else executions end),2) ||' | '|| round(DIRECT_WRITES /(case when executions=0 then 1 else executions end),2) "BUF_GET|DISK_R|DIRECT_W", |
|
--round(PERSISTENT_MEM/1024/1024,2) "P_MEM_MB", |
|
substr(MODULE,1,15)"MODULE", FIRST_LOAD_TIME, LAST_LOAD_TIME |
|
--,SQL_PLAN_BASELINE, SQL_PROFILE |
|
from v\$sql where SQL_ID='${SQLID}'; |
|
|
|
END; |
|
/ |
|
PRINT A; |
|
/ |
|
|
|
|
|
PROMPT |
|
PROMPT ************************* |
|
PROMPT BIND VARIABLES + SQL TEXT: |
|
PROMPT ************************* |
|
set heading off wrap on |
|
SET LONG 999999999 PAGESIZE 10000 LINESIZE 200 |
|
select 'VARIABLE '||trim (leading ':' from name)||' '||case when datatype_string= 'DATE' then 'VARCHAR2(60)' else datatype_string end||';' from v\$sql_bind_capture |
|
where SQL_ID='${SQLID}' and CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}'); |
|
select 'EXECUTE '||name||' := '||''''||value_string||''''||';' from v\$sql_bind_capture |
|
where SQL_ID='${SQLID}' and CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}'); |
|
select sql_fulltext from v\$sql where sql_id='${SQLID}' and CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql where SQL_ID='${SQLID}'); |
|
set heading on |
|
|
|
PROMPT |
|
set heading off |
|
select 'Notes: (11g Onwards)' from dual; |
|
PROMPT ------- |
|
|
|
select |
|
decode(IS_BIND_SENSITIVE,'Y','- The Bind Variables for this statement are Being CHANGED.','N','- The Bind Variables for this statement have NEVER CHANGED.'), |
|
decode(IS_BIND_AWARE,'Y','- Adaptive Cursor Sharing CHANGED the initial execution plan for that SQL_ID at least one time.','N',''), |
|
' Child Number: '||CHILD_NUMBER |
|
from v\$sql where sql_id='${SQLID}' and CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql where SQL_ID='${SQLID}'); |
|
set heading on |
|
|
|
/* |
|
PROMPT |
|
PROMPT |
|
PROMPT ********************* |
|
PROMPT BIND VARIABLE VALUES: |
|
PROMPT ********************* |
|
|
|
col BIND_VARIABLE for a20 |
|
col VALUE for a100 |
|
col DATATYPE for a20 |
|
select name BIND_VARIABLE,value_string VALUE,datatype_string DATATYPE from v\$sql_bind_capture |
|
where SQL_ID='${SQLID}' and CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}'); |
|
|
|
PROMPT SEARCH STATSPACK TABLES: [May take very long time] |
|
PROMPT *********************** |
|
|
|
select SQL_TEXT from STATS\$SQLTEXT where sql_id='${SQLID}'; |
|
select executions from STATS\$SQL_SUMMARY where sql_id='${SQLID}'; |
|
|
|
*/ |
|
|
|
PROMPT |
|
PROMPT |
|
PROMPT ********************* |
|
PROMPT EXECUTION PLAN: |
|
PROMPT ********************* |
|
|
|
col PLAN_TABLE_OUTPUT for a156 |
|
--SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR(('${SQLID}'))); |
|
select plan_table_output from table(dbms_xplan.display_cursor('${SQLID}',null,'all')); |
|
|
|
PROMPT |
|
PROMPT ****************************** |
|
PROMPT Execution Plan History Summary: [Change of PLAN_HASH_VALUE means a new Execution Plan] |
|
PROMPT ****************************** |
|
|
|
select distinct to_char(TIMESTAMP,'DD-MON-YY HH24:MI:SS') TIMESTAMP,SQL_ID,PLAN_HASH_VALUE from DBA_HIST_SQL_PLAN where sql_id='${SQLID}' group by TIMESTAMP,SQL_ID,PLAN_HASH_VALUE order by TIMESTAMP; |
|
|
|
PROMPT |
|
PROMPT |
|
PROMPT *********************** |
|
PROMPT EXECUTION PLAN History: Written By: Tim Gorman (Evergreen Database Technologies, Inc.) |
|
PROMPT *********************** |
|
/********************************************************************** |
|
* File: sqlhistory.sql |
|
* Type: SQL*Plus script |
|
* Author: Tim Gorman (Evergreen Database Technologies, Inc.) |
|
* Date: 29sep08 |
|
* |
|
* Description: |
|
* SQL*Plus script to query the "history" of a specified SQL |
|
* statement, using its "SQL ID" across all database instances |
|
* in a database, using the AWR repository. This report is useful |
|
* for obtaining an hourly perspective on SQL statements seen in |
|
* more aggregated reports. |
|
* |
|
* Modifications: |
|
* TGorman 29sep08 adapted from the earlier STATSPACK-based |
|
* "sphistory.sql" script |
|
*********************************************************************/ |
|
set echo off |
|
set feedback off timing off verify off linesize 200 pages 50000 recsep off echo off |
|
set serveroutput on size 1000000 |
|
col phv heading "Plan|Hash Value" |
|
col snap_time format a12 truncate heading "Snapshot|Time" |
|
col execs format 999,999,990 heading "Execs" |
|
col lio_per_exec format 999,999,999,990.00 heading "Avg Logical IO|Per Exec" |
|
col pio_per_exec format 999,999,999,990.00 heading "Avg Physical IO|Per Exec" |
|
col cpu_per_exec format 999,999,999,990.00 heading "Avg|CPU (secs)|Per Exec" |
|
col ela_per_exec format 999,999,999,990.00 heading "Avg|Elapsed (secs)|Per Exec" |
|
col sql_text format a64 heading "Text of SQL statement" |
|
clear breaks computes |
|
ttitle off |
|
btitle off |
|
|
|
--variable v_nbr_days number |
|
|
|
|
|
declare |
|
cursor get_phv(in_sql_id in varchar2, in_days in integer) |
|
is |
|
select ss.plan_hash_value, |
|
min(s.begin_interval_time) min_time, |
|
max(s.begin_interval_time) max_time, |
|
min(s.snap_id) min_snap, |
|
max(s.snap_id) max_snap, |
|
sum(ss.executions_delta) sum_execs, |
|
sum(ss.disk_reads_delta) sum_disk_reads, |
|
sum(ss.buffer_gets_delta) sum_buffer_gets, |
|
sum(ss.cpu_time_delta)/1000000 sum_cpu_time, |
|
sum(ss.elapsed_time_delta)/1000000 sum_elapsed_time |
|
from dba_hist_sqlstat ss, |
|
dba_hist_snapshot s |
|
where ss.dbid = s.dbid |
|
and ss.instance_number = s.instance_number |
|
and ss.snap_id = s.snap_id |
|
and ss.sql_id = in_sql_id |
|
/* and ss.executions_delta > 0 */ |
|
and s.begin_interval_time >= sysdate-in_days |
|
group by ss.plan_hash_value |
|
order by sum_elapsed_time desc; |
|
-- |
|
cursor get_xplan(in_sql_id in varchar2, in_phv in number) |
|
is |
|
select plan_table_output |
|
from table(dbms_xplan.display_awr(in_sql_id, in_phv, null, 'ALL -ALIAS')); |
|
-- |
|
v_prev_plan_hash_value number := -1; |
|
v_text_lines number := 0; |
|
v_errcontext varchar2(100); |
|
v_errmsg varchar2(100); |
|
v_display_sql_text boolean; |
|
-- |
|
begin |
|
/* |
|
v_errcontext := 'query NBR_DAYS from DUAL'; |
|
select decode('100','',10,to_number(nvl('100','10'))) |
|
into :v_nbr_days |
|
from dual; |
|
*/ |
|
v_errcontext := 'open/fetch get_phv'; |
|
--for phv in get_phv('${SQLID}', :v_nbr_days) loop |
|
for phv in get_phv('${SQLID}', ${HIST_DAYS}) loop |
|
-- |
|
if get_phv%rowcount = 1 then |
|
-- |
|
dbms_output.put_line('+'|| |
|
rpad('-',12,'-')|| |
|
rpad('-',10,'-')|| |
|
rpad('-',10,'-')|| |
|
rpad('-',12,'-')|| |
|
rpad('-',15,'-')|| |
|
rpad('-',15,'-')|| |
|
rpad('-',12,'-')|| |
|
rpad('-',12,'-')||'+'); |
|
dbms_output.put_line('|'|| |
|
rpad('Plan HV',12,' ')|| |
|
rpad('Min Snap',10,' ')|| |
|
rpad('Max Snap',10,' ')|| |
|
rpad('Execs',12,' ')|| |
|
rpad('LIO',15,' ')|| |
|
rpad('PIO',15,' ')|| |
|
rpad('CPU',12,' ')|| |
|
rpad('Elapsed',12,' ')||'|'); |
|
dbms_output.put_line('+'|| |
|
rpad('-',12,'-')|| |
|
rpad('-',10,'-')|| |
|
rpad('-',10,'-')|| |
|
rpad('-',12,'-')|| |
|
rpad('-',15,'-')|| |
|
rpad('-',15,'-')|| |
|
rpad('-',12,'-')|| |
|
rpad('-',12,'-')||'+'); |
|
-- |
|
end if; |
|
-- |
|
dbms_output.put_line('|'|| |
|
rpad(trim(to_char(phv.plan_hash_value)),12,' ')|| |
|
rpad(trim(to_char(phv.min_snap)),10,' ')|| |
|
rpad(trim(to_char(phv.max_snap)),10,' ')|| |
|
rpad(trim(to_char(phv.sum_execs,'999,999,990')),12,' ')|| |
|
rpad(trim(to_char(phv.sum_buffer_gets,'999,999,999,990')),15,' ')|| |
|
rpad(trim(to_char(phv.sum_disk_reads,'999,999,999,990')),15,' ')|| |
|
rpad(trim(to_char(phv.sum_cpu_time,'999,990.00')),12,' ')|| |
|
rpad(trim(to_char(phv.sum_elapsed_time,'999,990.00')),12,' ')||'|'); |
|
-- |
|
v_errcontext := 'fetch/close get_phv'; |
|
-- |
|
end loop; |
|
dbms_output.put_line('+'|| |
|
rpad('-',12,'-')|| |
|
rpad('-',10,'-')|| |
|
rpad('-',10,'-')|| |
|
rpad('-',12,'-')|| |
|
rpad('-',15,'-')|| |
|
rpad('-',15,'-')|| |
|
rpad('-',12,'-')|| |
|
rpad('-',12,'-')||'+'); |
|
-- |
|
v_errcontext := 'open/fetch get_phv'; |
|
--for phv in get_phv('${SQLID}', :v_nbr_days) loop |
|
for phv in get_phv('${SQLID}', ${HIST_DAYS}) loop |
|
-- |
|
if v_prev_plan_hash_value <> phv.plan_hash_value then |
|
-- |
|
v_prev_plan_hash_value := phv.plan_hash_value; |
|
v_display_sql_text := FALSE; |
|
-- |
|
v_text_lines := 0; |
|
v_errcontext := 'open/fetch get_xplan'; |
|
for s in get_xplan('${SQLID}', phv.plan_hash_value) loop |
|
-- |
|
if v_text_lines = 0 then |
|
dbms_output.put_line('.'); |
|
dbms_output.put_line('========== PHV = ' || |
|
phv.plan_hash_value || |
|
'=========='); |
|
dbms_output.put_line('First seen from "'|| |
|
to_char(phv.min_time,'MM/DD/YY HH24:MI:SS') || |
|
'" (snap #'||phv.min_snap||')'); |
|
dbms_output.put_line('Last seen from "'|| |
|
to_char(phv.max_time,'MM/DD/YY HH24:MI:SS') || |
|
'" (snap #'||phv.max_snap||')'); |
|
dbms_output.put_line('.'); |
|
dbms_output.put_line( |
|
rpad('Execs',15,' ')|| |
|
rpad('LIO',15,' ')|| |
|
rpad('PIO',15,' ')|| |
|
rpad('CPU',15,' ')|| |
|
rpad('Elapsed',15,' ')); |
|
dbms_output.put_line( |
|
rpad('=====',15,' ')|| |
|
rpad('===',15,' ')|| |
|
rpad('===',15,' ')|| |
|
rpad('===',15,' ')|| |
|
rpad('=======',15,' ')); |
|
dbms_output.put_line( |
|
rpad(trim(to_char(phv.sum_execs,'999,999,999,990')),15,' ')|| |
|
rpad(trim(to_char(phv.sum_buffer_gets,'999,999,999,990')),15,' ')|| |
|
rpad(trim(to_char(phv.sum_disk_reads,'999,999,999,990')),15,' ')|| |
|
rpad(trim(to_char(phv.sum_cpu_time,'999,999,990.00')),15,' ')|| |
|
rpad(trim(to_char(phv.sum_elapsed_time,'999,999,990.00')),15,' ')); |
|
dbms_output.put_line('.'); |
|
end if; |
|
-- |
|
if v_display_sql_text = FALSE and |
|
s.plan_table_output like 'Plan hash value: %' then |
|
-- |
|
v_display_sql_text := TRUE; |
|
-- |
|
end if; |
|
-- |
|
if v_display_sql_text = TRUE then |
|
-- |
|
dbms_output.put_line(s.plan_table_output); |
|
-- |
|
end if; |
|
-- |
|
v_text_lines := v_text_lines + 1; |
|
-- |
|
end loop; |
|
-- |
|
end if; |
|
-- |
|
v_errcontext := 'fetch/close get_phv'; |
|
-- |
|
end loop; |
|
-- |
|
exception |
|
when others then |
|
v_errmsg := sqlerrm; |
|
raise_application_error(-20000, v_errcontext || ': ' || v_errmsg); |
|
end; |
|
/ |
|
|
|
break on report |
|
compute sum of execs on report |
|
compute avg of lio_per_exec on report |
|
compute avg of pio_per_exec on report |
|
compute avg of cpu_per_exec on report |
|
compute avg of ela_per_exec on report |
|
ttitle center 'Summary Execution Statistics Over Time' |
|
select to_char(s.begin_interval_time, 'DD-MON HH24:MI') snap_time, |
|
ss.executions_delta execs, |
|
ss.buffer_gets_delta/decode(ss.executions_delta,0,1,ss.executions_delta) lio_per_exec, |
|
ss.disk_reads_delta/decode(ss.executions_delta,0,1,ss.executions_delta) pio_per_exec, |
|
(ss.cpu_time_delta/1000000)/decode(ss.executions_delta,0,1,ss.executions_delta) cpu_per_exec, |
|
(ss.elapsed_time_delta/1000000)/decode(ss.executions_delta,0,1,ss.executions_delta) ela_per_exec |
|
from dba_hist_snapshot s, |
|
dba_hist_sqlstat ss |
|
where ss.dbid = s.dbid |
|
and ss.instance_number = s.instance_number |
|
and ss.snap_id = s.snap_id |
|
and ss.sql_id = '${SQLID}' |
|
/* and ss.executions_delta > 0 */ |
|
--and s.begin_interval_time >= sysdate - :v_nbr_days |
|
and s.begin_interval_time >= sysdate - ${HIST_DAYS} |
|
order by s.snap_id; |
|
clear breaks computes |
|
|
|
set verify on echo on feedback on |
|
ttitle off |
|
|
|
PROMPT |
|
PROMPT ****************************** |
|
PROMPT Execution Plan History Summary: [Change of PLAN_HASH_VALUE means a new Execution Plan] |
|
PROMPT ****************************** |
|
|
|
select distinct to_char(TIMESTAMP,'DD-MON-YY HH24:MI:SS') TIMESTAMP,SQL_ID,PLAN_HASH_VALUE from DBA_HIST_SQL_PLAN where sql_id='${SQLID}' group by TIMESTAMP,SQL_ID,PLAN_HASH_VALUE order by TIMESTAMP; |
|
|
|
/* |
|
PROMPT |
|
PROMPT *********************** |
|
PROMPT SQL PLAN BASELINE: [For ${SQLID}] |
|
PROMPT *********************** |
|
|
|
col signature format 99999999999999999999 |
|
col sql_handle format a25 |
|
col plan_name format a30 |
|
col ELAPSED_TIME for 9999999.99 |
|
col CPU_TIME for 9999999.99 |
|
col BUFFER_GETS for 9999999.99 |
|
col enabled format a5 |
|
col accepted format a5 |
|
col fixed format a5 |
|
|
|
select distinct d.plan_name, d.sql_handle, d.signature, d.OPTIMIZER_COST COST, d.executions, |
|
round(d.ELAPSED_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) ELAPS_TIME, |
|
round(d.CPU_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) CPU_TIME, |
|
round(d.BUFFER_GETS /1000000/(case when d.executions=0 then 1 else d.executions end),2) BUFFER_GETS, |
|
d.enabled, d.accepted, d.fixed, |
|
to_char(d.LAST_EXECUTED,'DDMONYY HH24:MI:SS') LAST_EXECUTED |
|
from dba_sql_plan_baselines d, v\$sql s |
|
where s.sql_id='${SQLID}' |
|
and d.signature = s.exact_matching_signature |
|
--and s.CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}') |
|
; |
|
*/ |
|
|
|
EOF |
|
|
|
# ###################################### |
|
# Checking the Existance of SPM Feature: |
|
# ###################################### |
|
CHK_SPM_OPTION_RAW=$(${ORACLE_HOME}/bin/sqlplus -S "/ as sysdba" << EOF |
|
set pages 0 feedback off echo off; |
|
SELECT count(*) from v\$option where parameter='SQL Plan Management' and value='TRUE'; |
|
exit; |
|
EOF |
|
) |
|
CHK_SPM_OPTION=`echo ${CHK_SPM_OPTION_RAW} | awk '{print $NF}'` |
|
|
|
# IF SPM feature is available offer the option of fixing the SQL Plan through creating a BASELINE: |
|
if [ ${CHK_SPM_OPTION} -eq 1 ] |
|
then |
|
|
|
|
|
|
|
BASELINE_PLAN_COUNT_RAW=$(${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set pages 0 feedback off; |
|
SELECT COUNT(*) |
|
from dba_sql_plan_baselines d, v\$sql s |
|
where s.sql_id='${SQLID}' |
|
and d.signature = s.exact_matching_signature |
|
--and s.CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}') |
|
; |
|
exit; |
|
EOF |
|
) |
|
|
|
BASELINE_PLAN_COUNT=`echo ${BASELINE_PLAN_COUNT_RAW}| awk '{print $NF}'` |
|
|
|
# IF no Baseline found, offer to create a new baseline from current available plans from CURSOR CACHE and fix the plan: |
|
|
|
if [ ${BASELINE_PLAN_COUNT} -le 0 ] |
|
then |
|
echo "" |
|
echo "Do you want to FIX a plan for [${SQLID}] by creating a NEW BASELINE: [Y|N]" |
|
echo "=========================================================================" |
|
while read INPUT |
|
do |
|
case ${INPUT} in |
|
y|Y|yes|YES|Yes) |
|
echo "" |
|
echo "Creating a BASELINE for [${SQLID}] containing the current loaded plans from cursor cache" |
|
PLANS_COUNT_RAW=$(${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set pages 0 feedback off; |
|
set serveroutput on |
|
declare |
|
plans_loaded pls_integer ; |
|
begin |
|
plans_loaded := dbms_spm.load_plans_from_cursor_cache( sql_id => '${SQLID}' ) ; |
|
dbms_output.put_line( 'plans loaded: '||plans_loaded ) ; |
|
end ; |
|
/ |
|
exit; |
|
EOF |
|
) |
|
|
|
PLANS_COUNT=`echo ${PLANS_COUNT_RAW}| awk '{print $NF}'` |
|
|
|
if [ ${PLANS_COUNT} -gt 0 ] |
|
then |
|
echo "" |
|
echo "Loaded Plans: ${PLANS_COUNT}" |
|
echo "" |
|
${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set pages 1000 lines 169 pages 50000 long 2000000000 |
|
col signature format 99999999999999999999 |
|
col sql_handle format a25 |
|
col plan_name format a30 |
|
col ELAPSED_TIME for 9999999.99 |
|
col CPU_TIME for 9999999.99 |
|
col BUFFER_GETS for 9999999.99 |
|
col enabled format a5 |
|
col accepted format a5 |
|
col fixed format a5 |
|
|
|
PROMPT |
|
PROMPT CURRENT PLANS INSIDE THE NEW BASELINE for [${SQLID}]: |
|
PROMPT |
|
select distinct d.plan_name, d.sql_handle, d.signature, d.OPTIMIZER_COST COST, d.executions, |
|
round(d.ELAPSED_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) ELAPSED_TIME, |
|
round(d.CPU_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) CPU_TIME, |
|
round(d.BUFFER_GETS /1000000/(case when d.executions=0 then 1 else d.executions end),2) BUFFER_GETS, |
|
d.enabled, d.accepted, d.fixed |
|
from dba_sql_plan_baselines d, v\$sql s |
|
where sql_id='${SQLID}' |
|
and d.signature = s.exact_matching_signature |
|
--and s.CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}') |
|
; |
|
EOF |
|
|
|
read -p "Enter the PLAN_NAME for the plan you want to fix [From the above output]: " PLAN_NAME |
|
read -p "Enter the SQL_HANDLE for the plan you want to fix [From the above output]: " SQL_HANDLE |
|
echo "" |
|
|
|
${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set pages 1000 feedback off lines 169 long 2000000000 |
|
col signature format 99999999999999999999 |
|
col sql_handle format a25 |
|
col plan_name format a30 |
|
col ELAPSED_TIME for 9999999.99 |
|
col CPU_TIME for 9999999.99 |
|
col BUFFER_GETS for 9999999.99 |
|
col enabled format a5 |
|
col accepted format a5 |
|
col fixed format a5 |
|
|
|
set serveroutput on |
|
declare |
|
plans_loaded pls_integer ; |
|
begin |
|
plans_loaded := dbms_spm.alter_sql_plan_baseline( |
|
sql_handle => '${SQL_HANDLE}', |
|
plan_name => '${PLAN_NAME}', |
|
attribute_name => 'fixed', |
|
attribute_value =>'YES' |
|
) ; |
|
dbms_output.put_line( 'plans modified: '||plans_loaded ) ; |
|
end ; |
|
/ |
|
|
|
PROMPT |
|
select distinct d.plan_name, d.sql_handle, d.signature, d.OPTIMIZER_COST COST, d.executions, |
|
round(d.ELAPSED_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) ELAPSED_TIME, |
|
round(d.CPU_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) CPU_TIME, |
|
round(d.BUFFER_GETS /1000000/(case when d.executions=0 then 1 else d.executions end),2) BUFFER_GETS, |
|
d.enabled, d.accepted, d.fixed |
|
from dba_sql_plan_baselines d, v\$sql s |
|
where sql_id='${SQLID}' |
|
and d.signature = s.exact_matching_signature |
|
--and s.CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}') |
|
; |
|
|
|
set escape on feedback off echo off pages 0 |
|
-- Set SQL_HANDLE: |
|
column SQL_HANDLE NEW_VALUE SQL_HANDLE; |
|
select distinct d.sql_handle SQL_HANDLE from dba_sql_plan_baselines d, v\$sql s where sql_id='${SQLID}' and d.signature = s.exact_matching_signature; |
|
|
|
PROMPT |
|
PROMPT -- TO ADD a PLAN to the BASELINE: [From SQLPlus] [Provide the PLAN HASH VALUE] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.load_plans_from_cursor_cache(sql_id => '${SQLID}', plan_hash_value => '\&PLAN_HASH_VALUE', sql_handle => '&SQL_HANDLE');; |
|
|
|
PROMPT |
|
PROMPT -- TO DROP a PLAN: [From SQLPlus] [Provide the PLAN NAME] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.drop_sql_plan_baseline(plan_name => '\&PLAN_NAME');; |
|
|
|
PROMPT |
|
PROMPT -- TO DROP the BASELINE: [From SQLPlus] [FOR ROLLBACK PURPOSE] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.drop_sql_plan_baseline(sql_handle => '&SQL_HANDLE');; |
|
PROMPT |
|
|
|
EOF |
|
fi |
|
break;; |
|
*) break;; |
|
esac |
|
done |
|
fi |
|
|
|
# IF SQL BASELINE is already exist, but having more than one plan, offer the option to change/fix the plan from the list of baseline plans: |
|
#if [ ${BASELINE_PLAN_COUNT} -gt 1 ] |
|
if [ ${BASELINE_PLAN_COUNT} -ge 1 ] |
|
then |
|
#echo "" |
|
#echo -e "\033[33;5mMultiple Plans Detected for this SQLID ...\033[0m" |
|
echo "" |
|
${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
PROMPT |
|
PROMPT *********************** |
|
PROMPT SQL PLAN BASELINE: [For ${SQLID}] |
|
PROMPT *********************** |
|
|
|
set pages 1000 lines 169 pages 50000 long 2000000000 |
|
col signature format 99999999999999999999 |
|
col sql_handle format a25 |
|
col plan_name format a30 |
|
col ELAPSED_TIME for 9999999.99 |
|
col CPU_TIME for 9999999.99 |
|
col BUFFER_GETS for 9999999.99 |
|
col enabled format a5 |
|
col accepted format a5 |
|
col fixed format a5 |
|
col LAST_EXECUTED format a13 |
|
|
|
select distinct d.plan_name, d.sql_handle, d.signature, d.OPTIMIZER_COST COST, d.executions, |
|
round(d.ELAPSED_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) ELAPS_TIME, |
|
round(d.CPU_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) CPU_TIME, |
|
round(d.BUFFER_GETS /1000000/(case when d.executions=0 then 1 else d.executions end),2) BUFFER_GETS, |
|
d.enabled, d.accepted, d.fixed, |
|
to_char(d.LAST_EXECUTED,'DDMONYY HH24:MI') LAST_EXECUTED |
|
from dba_sql_plan_baselines d, v\$sql s |
|
where s.sql_id='${SQLID}' |
|
and d.signature = s.exact_matching_signature |
|
--and s.CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}') |
|
; |
|
|
|
set escape on feedback off echo off pages 0 |
|
-- Set SQL_HANDLE: |
|
column SQL_HANDLE NEW_VALUE SQL_HANDLE |
|
select distinct d.sql_handle SQL_HANDLE from dba_sql_plan_baselines d, v\$sql s where sql_id='${SQLID}' and d.signature = s.exact_matching_signature; |
|
|
|
PROMPT |
|
PROMPT -- TO ADD a PLAN to the BASELINE: [From SQLPlus] [Provide the PLAN HASH VALUE] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.load_plans_from_cursor_cache(sql_id => '${SQLID}', plan_hash_value => '\&PLAN_HASH_VALUE', sql_handle => '&SQL_HANDLE');; |
|
|
|
PROMPT |
|
PROMPT -- TO DROP a PLAN: [From SQLPlus] [Provide the PLAN NAME] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.drop_sql_plan_baseline(plan_name => '\&PLAN_NAME');; |
|
|
|
PROMPT |
|
PROMPT -- TO DROP the BASELINE: [From SQLPlus] [FOR ROLLBACK PURPOSE] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.drop_sql_plan_baseline(sql_handle => '&SQL_HANDLE');; |
|
EOF |
|
|
|
echo "" |
|
echo "Do you want to FIX a plan for [${SQLID}] in the CURRENT exist BASELINE: [Y|N]" |
|
echo "============================================================================" |
|
while read ANS |
|
do |
|
case ${ANS} in |
|
y|Y|yes|YES|Yes) |
|
echo "" |
|
read -p "Enter the PLAN_NAME for the plan you want to fix [From the above query output]: " PLAN_NAME |
|
read -p "Enter the SQL_HANDLE for the plan you want to fix [From the above query output]: " SQL_HANDLE |
|
echo "" |
|
${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set pages 1000 feedback off lines 169 pages 50000 long 2000000000 |
|
col signature format 99999999999999999999 |
|
col sql_handle format a25 |
|
col plan_name format a30 |
|
col ELAPSED_TIME for 9999999.99 |
|
col CPU_TIME for 9999999.99 |
|
col BUFFER_GETS for 9999999.99 |
|
col enabled format a5 |
|
col accepted format a5 |
|
col fixed format a5 |
|
|
|
set serveroutput on |
|
declare |
|
plans_loaded pls_integer ; |
|
begin |
|
plans_loaded := dbms_spm.alter_sql_plan_baseline( |
|
sql_handle => '${SQL_HANDLE}', |
|
plan_name => '${PLAN_NAME}', |
|
attribute_name => 'fixed', |
|
attribute_value =>'YES' |
|
) ; |
|
dbms_output.put_line( 'plans modified: '||plans_loaded ) ; |
|
end ; |
|
/ |
|
|
|
PROMPT |
|
select distinct d.plan_name, d.sql_handle, d.signature, d.OPTIMIZER_COST COST, d.executions, |
|
round(d.ELAPSED_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) ELAPSED_TIME, |
|
round(d.CPU_TIME /1000000/(case when d.executions=0 then 1 else d.executions end),2) CPU_TIME, |
|
round(d.BUFFER_GETS /1000000/(case when d.executions=0 then 1 else d.executions end),2) BUFFER_GETS, |
|
d.enabled, d.accepted, d.fixed |
|
from dba_sql_plan_baselines d, v\$sql s |
|
where sql_id='${SQLID}' |
|
and d.signature = s.exact_matching_signature |
|
--and s.CHILD_NUMBER = (select max(CHILD_NUMBER) from v\$sql_bind_capture where SQL_ID='${SQLID}') |
|
; |
|
|
|
set escape on feedback off echo off pages 0 |
|
-- Set SQL_HANDLE: |
|
column SQL_HANDLE NEW_VALUE SQL_HANDLE |
|
select distinct d.sql_handle SQL_HANDLE from dba_sql_plan_baselines d, v\$sql s where sql_id='${SQLID}' and d.signature = s.exact_matching_signature; |
|
|
|
PROMPT |
|
PROMPT -- TO ADD a PLAN to the BASELINE: [From SQLPlus] [Provide the PLAN HASH VALUE] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.load_plans_from_cursor_cache(sql_id => '${SQLID}', plan_hash_value => '\&PLAN_HASH_VALUE', sql_handle => '&SQL_HANDLE');; |
|
|
|
PROMPT |
|
PROMPT -- TO DROP a PLAN: [From SQLPlus] [Provide the PLAN NAME] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.drop_sql_plan_baseline(plan_name => '\&PLAN_NAME');; |
|
|
|
PROMPT |
|
PROMPT -- TO DROP the BASELINE: [From SQLPlus] [FOR ROLLBACK PURPOSE] |
|
PROMPT var pls number |
|
PROMPT exec :pls := dbms_spm.drop_sql_plan_baseline(sql_handle => '&SQL_HANDLE');; |
|
PROMPT |
|
|
|
EOF |
|
break;; |
|
*) break;; |
|
esac |
|
done |
|
fi |
|
|
|
fi |
|
|
|
VAL_TUN_TASK_RAW=$(${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set pages 0 feedback off; |
|
SELECT COUNT(*) FROM DBA_ADVISOR_TASKS where TASK_NAME='${SQLID}_Tuning_Task'; |
|
EOF |
|
) |
|
VAL_TUN_TASK=`echo ${VAL_TUN_TASK_RAW}| awk '{print $NF}'` |
|
case ${VAL_TUN_TASK} in |
|
1) echo |
|
echo "-----------------------------------------------------------------------------------------------" |
|
# echo -e "\033[33;5mA Tuning Task already been found for SQLID [${SQLID}] You can view this task result using:\033[0m" |
|
echo -e "\033[33;5mA Tuning Task already been found for SQLID [${SQLID}]\033[0m" |
|
echo "Displaying the Recommendations:" |
|
echo "-----------------------------------------------------------------------------------------------" |
|
# echo "SET LONG 2000000000 pages 10000 lines 200" |
|
# echo "SELECT DBMS_SQLTUNE.report_tuning_task('${SQLID}_Tuning_Task') AS recommendations FROM dual;";; |
|
${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
SET LONG 999999999 PAGESIZE 10000 LINESIZE 167 |
|
SELECT DBMS_SQLTUNE.report_tuning_task('${SQLID}_Tuning_Task') AS recommendations FROM dual; |
|
EOF |
|
;; |
|
esac |
|
|
|
echo "" |
|
printf "`echo "Do you want to Tune SQLID [${SQLID}] Using SQL Tuning Advisor? (NO/YES) Default is [NO] |"` `echo -e "\033[33;5m[Licensed Feature]\033[0m"` \n" |
|
echo "===================================================================" |
|
echo "Note: Please make sure that Diagnostic & Tuning License is already acquired before using this feature." |
|
while read ANS1 |
|
do |
|
case ${ANS1} in |
|
""|n|N|no|NO|No) break ;; |
|
""|y|Y|yes|YES|Yes) |
|
|
|
${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
--PROMPT |
|
--PROMPT SQL Statement Full Text: |
|
--PROMPT ----------------------- |
|
|
|
--SET LONG 2000000000 PAGESIZE 10000 LINESIZE 200 |
|
--col SQL_FULLTEXT for a200 |
|
--select SQL_FULLTEXT from V\$SQL where SQL_ID='${SQLID}'; |
|
|
|
PROMPT |
|
PROMPT Creating SQL Tuning Task: "${SQLID}_Tuning_Task" ... |
|
DECLARE |
|
l_sql_tune_task_id VARCHAR2(100); |
|
BEGIN |
|
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( |
|
sql_id => '${SQLID}', |
|
scope => DBMS_SQLTUNE.scope_comprehensive, |
|
time_limit => 3600, |
|
task_name => '${SQLID}_Tuning_Task', |
|
description => 'Tuning task for statement ${SQLID}'); |
|
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id); |
|
END; |
|
/ |
|
|
|
PROMPT Executing TUNING Task: "${SQLID}_Tuning_Task" ... |
|
PROMPT |
|
PROMPT Please Wait! This May Take Several Minutes ... |
|
EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => '${SQLID}_Tuning_Task'); |
|
|
|
PROMPT |
|
PROMPT SQL Tuning Recommendations: |
|
PROMPT -------------------------- |
|
|
|
spool ${SQLID}_Tuning_Task_details.log |
|
SET LONG 999999999 PAGESIZE 10000 LINESIZE 200 |
|
SELECT DBMS_SQLTUNE.report_tuning_task('${SQLID}_Tuning_Task') AS recommendations FROM dual; |
|
|
|
PROMPT |
|
PROMPT Post Tuning: You may need to enforce HARD PARSING this statement to enforce using the new execution plan: |
|
PROMPT ----------- |
|
|
|
PROMPT SELECT CHILD_NUMBER,ADDRESS,HASH_VALUE,LAST_LOAD_TIME FROM V\$SQL WHERE SQL_ID='${SQLID}';; |
|
PROMPT EXEC FOR I IN (SELECT ADDRESS,HASH_VALUE,USERS_EXECUTING,SQL_TEXT FROM V\$SQLAREA WHERE SQL_ID='${SQLID}') LOOP SYS.DBMS_SHARED_POOL.PURGE(I.ADDRESS||','||I.HASH_VALUE,'C'); END LOOP;; |
|
PROMPT SELECT CHILD_NUMBER,ADDRESS,HASH_VALUE,LAST_LOAD_TIME FROM V\$SQL WHERE SQL_ID='${SQLID}';; |
|
|
|
PROMPT |
|
PROMPT For Dropping Tuning Task "${SQLID}_Tuning_Task" Use this SQL command: |
|
PROMPT ------------------------ |
|
|
|
PROMPT EXEC dbms_sqltune.drop_tuning_task(task_name => '${SQLID}_Tuning_Task');; |
|
PROMPT |
|
spool off |
|
|
|
EOF |
|
break ;; |
|
*) echo "Please enter a VALID answer [N|Y]" ;; |
|
esac |
|
done |
|
|
|
break |
|
else |
|
echo |
|
echo "SQLID [${SQLID}] is not found in the SHARED POOL!" |
|
echo |
|
echo "Searching the AWR ..." |
|
echo |
|
|
|
AWR_COUNT_RAW=$(${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set feedback off |
|
select count(*) from table(dbms_xplan.display_awr('${SQLID}')); |
|
EOF |
|
) |
|
AWR_COUNT=`echo ${AWR_COUNT_RAW}| awk '{print $NF}'` |
|
|
|
if [ ${AWR_COUNT} -gt 0 ] |
|
then |
|
echo "SQLID found in AWR." |
|
echo |
|
echo "Displaying the Execution Plans History ..." |
|
echo |
|
|
|
${ORACLE_HOME}/bin/sqlplus -s '/ as sysdba' << EOF |
|
set feedback off |
|
set linesize 159 pages 50000 long 2000000000 |
|
col PLAN_TABLE_OUTPUT for a156 |
|
select * from table(dbms_xplan.display_awr('${SQLID}')); |
|
EOF |
|
|
|
else |
|
echo "The given SQLID is NOT found neither in the Shared Pool nor in AWR!" |
|
echo "" |
|
fi |
|
break |
|
fi |
|
done |
|
|
|
# ############# |
|
# END OF SCRIPT |
|
# ############# |
|
# REPORT BUGS to: <mahmmoudadel@hotmail.com>. |
|
# DISCLAIMER: THIS SCRIPT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY. IT IS PROVIDED "AS IS". |
|
# DOWNLOAD THE LATEST VERSION OF DATABASE ADMINISTRATION BUNDLE FROM: http://dba-tips.blogspot.com/2014/02/oracle-database-administration-scripts.html |