2026-03-12 20:23:15

This commit is contained in:
root
2026-03-12 21:23:47 +01:00
parent eab4b36eca
commit 93039b8489
3332 changed files with 699614 additions and 0 deletions

7
Kevin_Meade/afiedt.buf Normal file
View File

@@ -0,0 +1,7 @@
SELECT column_id,
column_name,
histogram
FROM user_tab_columns
WHERE table_name = 'R3'
ORDER BY column_id
/

View File

@@ -0,0 +1,97 @@
--
-- load qep information into the plan_table from gv$sql_plan
--
-- requires you to identify the inst_id,sql_id,child_number first
--
-- parameter 1 = inst_id
-- parameter 2 = sql_id
-- parameter 3 = child_number
--
-- @loadplanfromcache11g.sql 1 6zcb0r0rch025 0
--
-- then use the normal plan_table scripts to get the goodness
--
-- @showplan11g
-- @showplandatamodel11g
-- ...
--
insert into plan_table
(
PLAN_ID
,TIMESTAMP
,REMARKS
,OPERATION
,OPTIONS
,OBJECT_NODE
,OBJECT_OWNER
,OBJECT_NAME
,OBJECT_ALIAS
,object_instance
,OBJECT_TYPE
,OPTIMIZER
,SEARCH_COLUMNS
,ID
,PARENT_ID
,DEPTH
,POSITION
,COST
,CARDINALITY
,BYTES
,OTHER_TAG
,PARTITION_START
,PARTITION_STOP
,PARTITION_ID
,OTHER
,OTHER_XML
,DISTRIBUTION
,CPU_COST
,IO_COST
,TEMP_SPACE
,ACCESS_PREDICATES
,FILTER_PREDICATES
,PROJECTION
,TIME
,QBLOCK_NAME
)
select
nvl((select max(plan_id) from plan_table),0)+1 plan_id
,TIMESTAMP
,REMARKS
,OPERATION
,OPTIONS
,OBJECT_NODE
,OBJECT_OWNER
,OBJECT_NAME
,OBJECT_ALIAS
,OBJECT# object_instance
,OBJECT_TYPE
,OPTIMIZER
,SEARCH_COLUMNS
,ID
,PARENT_ID
,DEPTH
,POSITION
,COST
,CARDINALITY
,BYTES
,OTHER_TAG
,PARTITION_START
,PARTITION_STOP
,PARTITION_ID
,OTHER
,OTHER_XML
,DISTRIBUTION
,CPU_COST
,IO_COST
,TEMP_SPACE
,ACCESS_PREDICATES
,FILTER_PREDICATES
,PROJECTION
,TIME
,QBLOCK_NAME
from gv$sql_plan
where inst_id = &&1
and sql_id = '&&2'
and child_number = &&3
/

View File

@@ -0,0 +1,103 @@
--
-- load qep information into the plan_table from DBA_HIST_SQL_PLAN (history of monitored plans)
--
-- requires you to identify the sql_id and date of when you want your plan
-- does a bob barker lookup based on the date, for the sql_id supplied
-- note use of +1 second to the date in order to account for the millseconds in the timestamp
-- note also the use of a specific format mask 'rrrrmmddhh24miss'
-- often you will need to guess about the time unless you know it from some other place
--
-- parameter 1 = sql_id
-- parameter 2 = timestamp (in the right format)
--
-- @loadplanfromhist11g.sql 6zcb0r0rch025 2014080212:10:03
--
-- then use the normal plan_table scripts to get the goodness
--
-- @showplan11g
-- @showplandatamodel11g
-- ...
--
insert into plan_table
(
PLAN_ID
,TIMESTAMP
,REMARKS
,OPERATION
,OPTIONS
,OBJECT_NODE
,OBJECT_OWNER
,OBJECT_NAME
,OBJECT_ALIAS
,object_instance
,OBJECT_TYPE
,OPTIMIZER
,SEARCH_COLUMNS
,ID
,PARENT_ID
,DEPTH
,POSITION
,COST
,CARDINALITY
,BYTES
,OTHER_TAG
,PARTITION_START
,PARTITION_STOP
,PARTITION_ID
,OTHER
,OTHER_XML
,DISTRIBUTION
,CPU_COST
,IO_COST
,TEMP_SPACE
,ACCESS_PREDICATES
,FILTER_PREDICATES
,PROJECTION
,TIME
,QBLOCK_NAME
)
select
nvl((select max(plan_id) from plan_table),0)+1 plan_id
,TIMESTAMP
,REMARKS
,OPERATION
,OPTIONS
,OBJECT_NODE
,OBJECT_OWNER
,OBJECT_NAME
,OBJECT_ALIAS
,OBJECT# object_instance
,OBJECT_TYPE
,OPTIMIZER
,SEARCH_COLUMNS
,ID
,PARENT_ID
,DEPTH
,POSITION
,COST
,CARDINALITY
,BYTES
,OTHER_TAG
,PARTITION_START
,PARTITION_STOP
,PARTITION_ID
,OTHER
,OTHER_XML
,DISTRIBUTION
,CPU_COST
,IO_COST
,TEMP_SPACE
,ACCESS_PREDICATES
,FILTER_PREDICATES
,PROJECTION
,TIME
,QBLOCK_NAME
from dba_hist_sql_plan
where sql_id = '&&1'
and timestamp = (
select max(timestamp)
from dba_hist_sql_plan
where sql_id = '&&1'
and timestamp <= to_date('&&2','rrrrmmddhh24miss')+1/24/60/60
)
/

View File

@@ -0,0 +1,113 @@
--
-- show have fast scan operations
-- (sorting / hashing / table scans / index scans) will take
--
-- provides a MB/second metric that can be used to compare different systems
-- has plenty of flaws yet still works great
--
-- also provides an expected end time for the operation
-- though this can be misleading
--
-- usage is: @SHOWALLSCANRATES
--
--clear breaks
--clear computes
--clear columns
col time_remaining head 'Seconds|Remaining'
col scanned_blocks head 'Scanned Blocks|or Indexes'
col all_blocks head 'All Blocks|or Indexes'
col blocks_remaining head 'Blocks|or Indexes|Remaining' noprint
col opname format a16
col target format a40
col username format a15
col MB_per_Second form 990.0 head 'MB/s'
col pct_scanned head '%Scanned' format 990.00
col predicted_runtime_seconds head 'Estmd.|Runtime|Seconds'
col total_blocks head 'Total|Blocks|or|Indexes'
col sid format 99990
col block_size format 99990 head 'Block|Size'
col id_passes_temp format a25
break on inst_id skip page
with
scan_data as (
select
to_number(
substr(a.message
,instr(a.message,': ',1,2)+2
,instr(a.message,' out of ',1,1)-instr(a.message,': ',1,2)-1
)
)
/ to_number(
substr(a.message
,instr(a.message,' out of ',1,1)+8
,instr(a.message,' ',instr(a.message,' out of ',1,1)+8)-instr(a.message,' out of ',1,1)-7
)
) *100 pct_scanned
, to_number(
substr(a.message
,instr(a.message,' out of ',1,1)+8
,instr(a.message,' ',instr(a.message,' out of ',1,1)+8)-instr(a.message,' out of ',1,1)-7
)
)
- to_number(
substr(a.message
,instr(a.message,': ',1,2)+2
,instr(a.message,' out of ',1,1)-instr(a.message,': ',1,2)-1
)
) blocks_remaining
, a.time_remaining
, a.opname
, to_number(b.value) block_size
, a.target
, a.sid
, a.inst_id
, a.username
, a.sql_hash_value
from (
select
replace(gv$session_longops.message,'RMAN:','RMAN') message
, gv$session_longops.time_remaining
, gv$session_longops.opname
, nvl(gv$session_longops.target,replace(gv$session_longops.target_desc,'Table ')) target
, gv$session_longops.sid
, gv$session_longops.inst_id
, gv$session_longops.username
, gv$session_longops.sql_hash_value
from gv$session_longops
, gv$session
where gv$session_longops.sid = gv$session.sid
and gv$session_longops.inst_id = gv$session.inst_id
and gv$session_longops.sid = gv$session.sid
and gv$session_longops.serial# = gv$session.serial#
and gv$session_longops.time_remaining > 0
) a
,(select value from gv$parameter where name = 'db_block_size' and rownum = 1) b
)
select
scan_data.inst_id
, round(blocks_remaining*block_size/1024/1024/time_remaining,1) MB_per_Second
, scan_data.time_remaining
, round(time_remaining/(1-pct_scanned/100)) predicted_runtime_seconds
, scan_data.pct_scanned
, scan_data.blocks_remaining
, round(blocks_remaining/(1-pct_scanned/100)) total_blocks
, scan_data.opname
, scan_data.BLOCK_SIZE
, scan_data.target
, (
select
max(operation_id)||':'||DECODE(MAX(NUMBER_PASSES),0,'OPTIMAL',1,'ONE-PASS',NULL,NULL,'MULTI-PASS('||max(number_passes)||')')||DECODE(max(TEMPSEG_SIZE),NULL,NULL,','||round(max(TEMPSEG_SIZE)/1024/1024)||'M')
from gv$sql_workarea_active
where gv$sql_workarea_active.sid = scan_data.sid
and gv$sql_workarea_active.inst_id = scan_data.inst_id
-- and scan_data.opname in ('Hash Join','Sort Output')
-- and gv$sql_workarea_active.OPERATION_TYPE in ('HASH-JOIN','SORT','WINDOW (SORT)','GROUP BY (SORT)')
) id_passes_temp
, scan_data.sid
, scan_data.username
, scan_data.sql_hash_value
from scan_data
order by inst_id,username,sid,time_remaining
/

View File

@@ -0,0 +1,12 @@
--
-- show work areas in use
--
col SQL_EXEC_START noprint
col SQL_EXEC_ID noprint
col WORKAREA_ADDRESS noprint
col OPERATION_TYPE format a20 trunc
col active_time noprint
col expected_size noprint
select * from gv$sql_workarea_active;

View File

@@ -0,0 +1,76 @@
--
-- show all column stats for columns in the specified table
-- requires the function KEV_RAW_TO_STRING
-- very usefull for looking at column recorded HIGH/LOW
--
-- parameter 1 = owner
-- parameter 2 = table_name
--
-- usage is: @SHOWCOLSTATS <owner> <table_name>
--
/*
CREATE OR replace FUNCTION kev_raw_to_string (rawval RAW, TYPE VARCHAR2) RETURN VARCHAR2
IS
cn NUMBER;
cv VARCHAR2(32);
cd DATE;
cnv NVARCHAR2(32);
cr ROWID;
cc CHAR(32);
BEGIN
IF ( TYPE = 'NUMBER' ) THEN
dbms_stats.Convert_raw_value(rawval, cn);
RETURN '"'||cn||'"';
ELSIF ( TYPE = 'VARCHAR2' ) THEN
dbms_stats.Convert_raw_value(rawval, cv);
RETURN '"'||cv||'"';
ELSIF ( TYPE = 'DATE' ) THEN
dbms_stats.Convert_raw_value(rawval, cd);
RETURN '"'||to_char(cd,'dd-mon-rrrr.hh24:mi:ss')||'"';
ELSIF ( TYPE = 'NVARCHAR2' ) THEN
dbms_stats.Convert_raw_value(rawval, cnv);
RETURN '"'||cnv||'"';
ELSIF ( TYPE = 'ROWID' ) THEN
dbms_stats.Convert_raw_value(rawval, cr);
RETURN '"'||cnv||'"';
ELSIF ( TYPE = 'CHAR' ) THEN
dbms_stats.Convert_raw_value(rawval, cc);
RETURN '"'||cc||'"';
ELSE
RETURN '"UNSUPPORTED DATA_TYPE"';
END IF;
exception when others then
return '--- conversion error ---';
END;
/
*/
col low_value format a30
col high_value format a30
col last_analyzed format a22
--select table_name,column_name, num_distinct, num_nulls, num_buckets, sample_size,last_analyzed
select
OWNER
, TABLE_NAME
, COLUMN_NAME
, NUM_DISTINCT
, NUM_NULLS
, NUM_BUCKETS
, SAMPLE_SIZE
, AVG_COL_LEN
, DENSITY
, TO_CHAR(LAST_ANALYZED,'dd-mon-rrrr.hh24:mi:ss') last_analyzed
, GLOBAL_STATS
, USER_STATS
, km21378.kev_raw_to_string (LOW_VALUE,(select data_type from dba_tab_columns b where b.owner = a.owner and b.table_name = a.table_name and b.column_name = a.column_name)) LOW_VALUE
, km21378.kev_raw_to_string (HIGH_VALUE,(select data_type from dba_tab_columns b where b.owner = a.owner and b.table_name = a.table_name and b.column_name = a.column_name)) HIGH_VALUE
from dba_tab_col_statistics a
where (owner,table_name) in
(
(upper('&&1'),upper('&&2'))
)
--and (column_name = 'ROW_TERM_DATE$' or num_buckets > 1)
order by TABLE_NAME,COLUMN_NAME
/

View File

@@ -0,0 +1,39 @@
--
-- given a table
-- show is PK/UK/FK constraints
-- and FK constraints that point to it
--
-- usage is: @SHOWCONSTRAINTS <owner> <table_name>
--
break on constraint_name skip 1 on parent_table_name
col column_name format a30
col sort_order noprint
col select_id noprint
select a.owner,a.table_name,a.constraint_name,a.constraint_type,c.column_name,b.owner parent_child_owner,b.table_name parent_child_table_name,b.constraint_type,a.index_name,decode(a.constraint_type,'P',1,'U',2) sort_order,1 select_id
from dba_constraints a
,dba_constraints b
,dba_cons_columns c
where a.owner = upper('&&1')
and a.table_name = upper('&&2')
and a.r_owner = b.owner(+)
and a.r_constraint_name = b.constraint_name(+)
and a.owner = c.owner
and a.constraint_name = c.constraint_name
and a.constraint_type != 'C'
union all
select a.owner,a.table_name,a.constraint_name,a.constraint_type,c.column_name,b.owner parent_child_owner,b.table_name parent_child_table_name,b.constraint_type,a.index_name,decode(a.constraint_type,'P',1,'U',2) sort_order,2 select_id
from dba_constraints a
,dba_constraints b
,dba_cons_columns c
where b.owner = upper('&&1')
and b.table_name = upper('&&2')
and b.constraint_type in ('P','U')
and a.r_owner = b.owner
and a.r_constraint_name = b.constraint_name
and b.table_name != a.table_name
and a.owner = c.owner
and a.constraint_name = c.constraint_name
order by select_id,sort_order,owner,table_name,constraint_name,column_name
/

View File

@@ -0,0 +1,69 @@
/*
@gencardinalitycheckcode.sql dwstage ods_pega_report_group_assoc CASEID,CVRGPLNNBR,PLCYID,PEGARPRTGRPSTRTDT,LSSUNTNBR,FNDNGMTHDPLNNBR,EMPGRPID,CVRGCTGRYCD,CVRGTYPCD,FNDNGMTHDCD,RPRTGRPID,ROW_TERM_DATE,SOURCE 1
@gencardinalitycheckcode.sql dwstage ods_pega_report_group_assoc CASEID,CVRGPLNNBR,PLCYID,PEGARPRTGRPSTRTDT,LSSUNTNBR,FNDNGMTHDPLNNBR,EMPGRPID,CVRGCTGRYCD,CVRGTYPCD,FNDNGMTHDCD,RPRTGRPID,ROW_TERM_DATE,SOURCE 2
@gencardinalitycheckcode.sql dwstage ods_pega_report_group_assoc CASEID,CVRGPLNNBR,PLCYID,PEGARPRTGRPSTRTDT,LSSUNTNBR,FNDNGMTHDPLNNBR,EMPGRPID,CVRGCTGRYCD,CVRGTYPCD,FNDNGMTHDCD,RPRTGRPID,ROW_TERM_DATE,SOURCE 3
@gencardinalitycheckcode.sql dwstage ods_pega_report_group_assoc CASEID,CVRGPLNNBR,PLCYID,PEGARPRTGRPSTRTDT,LSSUNTNBR,FNDNGMTHDPLNNBR,EMPGRPID,CVRGCTGRYCD,CVRGTYPCD,FNDNGMTHDCD,RPRTGRPID,ROW_TERM_DATE,SOURCE 4
use this to get a starting point for best combination of columns based on distinct
note this still have the NULLS issue maybe (how do we handle columns with large % of null values)
but ignoring this, the technique is pretty solid
generate code and run it to find out how distinct different combinations of columns are
give some list of columns generate the possible combinations of columns restricted to a limited number (exp. combinations of N things taken M at a time)
results should point you to a good starting set of columns for an index given you list of columns you are intersted in
from this you use GENCARDINALITYCHECKCODE2.SQL
*/
with
table_data as (
select owner,table_name
from dba_tables
where owner = upper('&&1')
and table_name = upper('&&2')
)
, column_list as (
select dba_tab_columns.owner,dba_tab_columns.table_name,dba_tab_columns.column_name
from dba_tab_columns
,table_data
where dba_tab_columns.owner = table_data.owner
and dba_tab_columns.table_name = table_data.table_name
and instr(','||upper('&&3')||',',','||dba_tab_columns.column_name||',') > 0
)
, column_expression as (
select a.*
,length(sys_connect_by_path(a.column_name,','))-length(replace(sys_connect_by_path(a.column_name,','),',')) column_count
,substr(sys_connect_by_path(a.column_name,'||'',''||'),8) column_expression
from column_list a
connect by prior a.column_name < a.column_name
)
select 'clear columns' from dual union all
select 'col column_count newline' from dual union all
select 'col COLUMN_EXPRESSION format a800' from dual union all
select 'set linesize 999' from dual union all
select 'set pagesize 0' from dual union all
select 'set trimspool on' from dual union all
select 'set trimout on' from dual union all
--select 'set feedback off' from dual union all
--select 'set timing off' from dual union all
--select 'set time off' from dual union all
select '--owner table_name rowcount number_of_columns column_combo_cardinality column_expression' from dual union all
select 'select '''||table_data.owner||''' owner,'''||table_data.table_name||''' table_name,count(*) table_rowcount'
from table_data
union all
select *
from (
select ' ,'||column_expression.column_count||' column_count,count(distinct '||column_expression.column_expression||') expression_rowcount,'''||replace(column_expression.column_expression,chr(39),chr(39)||chr(39))||''' column_expression'
from column_expression
where column_count <= &&4
order by column_count,column_expression
)
union all
select 'from '||table_data.owner||'.'||table_data.table_name
from table_data
union all
select '/'
from table_data
/

View File

@@ -0,0 +1,29 @@
--
-- shows the histogram for a specific column
-- very usefull for showing when statistics might not help
--
-- parameter 1 = owner
-- parameter 2 = table_name
-- parameter 3 = column_name
--
-- usage is: @SHOWHISTOGRAM <owner> <table_name> <column_name>
--
COLUMN endpoint_actual_value noprint
COLUMN actual_value ON FORMAT a30
col column format a30
select b.*
,round(ratio_to_report(cardinality) over(partition by owner,table_name,column_name)*100) pct
,endpoint_actual_value actual_value
from (
select a.*
,ENDPOINT_NUMBER-nvl(lag(ENDPOINT_NUMBER) over(partition by owner,table_name,column_name order by endpoint_number),0) cardinality
from dba_histograms a
where owner = upper('&&1')
and table_name = upper('&&2')
and column_name = upper('&&3')
) b
order by owner,table_name,column_name,ENDPOINT_NUMBER
/

View File

@@ -0,0 +1,24 @@
--
-- for the given table
-- list the indexes on the table
--
-- parameter 1 = owner
-- parameter 2 = table_name
--
-- usage is: @SHOWINDEXES <owner> <table_name>
--
set verify off
break on index_name skip 1
col column_name format a30
select index_name,column_name
,(select index_type from dba_indexes b where b.owner = a.index_owner and b.index_name = a.index_name) index_type
,(select uniqueness from dba_indexes b where b.owner = a.index_owner and b.index_name = a.index_name) uniqueness
,(select tablespace_name from dba_indexes b where b.owner = a.index_owner and b.index_name = a.index_name) tablespace_name
from dba_ind_columns a
where table_name = upper('&&2')
and table_owner = upper('&&1')
order by 1,column_position
/

View File

@@ -0,0 +1,101 @@
--clear breaks
--clear computes
--clear columns
col time_remaining head 'Seconds|Remaining'
col scanned_blocks head 'Scanned Blocks|or Indexes'
col all_blocks head 'All Blocks|or Indexes'
col blocks_remaining head 'Blocks|or Indexes|Remaining' noprint
col opname format a16
col target format a40
col username format a15
col MB_per_Second form 990.0 head 'MB/s'
col pct_scanned head '%Scanned' format 990.00
col predicted_runtime_seconds head 'Estmd.|Runtime|Seconds'
col total_blocks head 'Total|Blocks|or|Indexes'
col sid format 99990
col block_size format 99990 head 'Block|Size'
col id_passes_temp format a25
break on inst_id skip page
with
scan_data as (
select
to_number(
substr(a.message
,instr(a.message,': ',1,2)+2
,instr(a.message,' out of ',1,1)-instr(a.message,': ',1,2)-1
)
)
/ to_number(
substr(a.message
,instr(a.message,' out of ',1,1)+8
,instr(a.message,' ',instr(a.message,' out of ',1,1)+8)-instr(a.message,' out of ',1,1)-7
)
) *100 pct_scanned
, to_number(
substr(a.message
,instr(a.message,' out of ',1,1)+8
,instr(a.message,' ',instr(a.message,' out of ',1,1)+8)-instr(a.message,' out of ',1,1)-7
)
)
- to_number(
substr(a.message
,instr(a.message,': ',1,2)+2
,instr(a.message,' out of ',1,1)-instr(a.message,': ',1,2)-1
)
) blocks_remaining
, a.time_remaining
, a.opname
, to_number(b.value) block_size
, a.target
, a.sid
, a.inst_id
, a.username
, a.sql_hash_value
from (
select
replace(gv$session_longops.message,'RMAN:','RMAN') message
, gv$session_longops.time_remaining
, gv$session_longops.opname
, nvl(gv$session_longops.target,replace(gv$session_longops.target_desc,'Table ')) target
, gv$session_longops.sid
, gv$session_longops.inst_id
, gv$session_longops.username
, gv$session_longops.sql_hash_value
from gv$session_longops
, gv$session
where gv$session_longops.sid = gv$session.sid
and gv$session_longops.inst_id = gv$session.inst_id
and gv$session_longops.sid = gv$session.sid
and gv$session_longops.serial# = gv$session.serial#
and gv$session_longops.time_remaining > 0
and gv$session_longops.username = user
) a
,(select value from gv$parameter where name = 'db_block_size' and rownum = 1) b
)
select
scan_data.inst_id
, round(blocks_remaining*block_size/1024/1024/time_remaining,1) MB_per_Second
, scan_data.time_remaining
, round(time_remaining/(1-pct_scanned/100)) predicted_runtime_seconds
, scan_data.pct_scanned
, scan_data.blocks_remaining
, round(blocks_remaining/(1-pct_scanned/100)) total_blocks
, scan_data.opname
, scan_data.BLOCK_SIZE
, scan_data.target
, (
select
max(operation_id)||':'||DECODE(MAX(NUMBER_PASSES),0,'OPTIMAL',1,'ONE-PASS',NULL,NULL,'MULTI-PASS('||max(number_passes)||')')||DECODE(max(TEMPSEG_SIZE),NULL,NULL,','||round(max(TEMPSEG_SIZE)/1024/1024)||'M')
from gv$sql_workarea_active
where gv$sql_workarea_active.sid = scan_data.sid
and gv$sql_workarea_active.inst_id = scan_data.inst_id
-- and scan_data.opname in ('Hash Join','Sort Output')
-- and gv$sql_workarea_active.OPERATION_TYPE in ('HASH-JOIN','SORT','WINDOW (SORT)','GROUP BY (SORT)')
) id_passes_temp
, scan_data.sid
, scan_data.username
, scan_data.sql_hash_value
from scan_data
order by inst_id,username,sid,time_remaining
/

View File

@@ -0,0 +1 @@
select * from gv$sql_workarea_active where (inst_id,sid) in (select inst_id,sid from gv$session where username = user);

12
Kevin_Meade/showowner.sql Normal file
View File

@@ -0,0 +1,12 @@
--
-- given an object name
-- show what schema owns it and what it is
--
col object_name format a30
select owner,object_type,object_name,status
from dba_objects
where object_name = upper('&&1')
order by 1,2,3
/

View File

@@ -0,0 +1,35 @@
col value format a30
col name format a40
col keyword format a10
break on keyword skip 1 dup
select decode(sign(instr(name,'dyn')),1,'dyn'
,decode(sign(instr(name,'size')),1,'size'
,decode(sign(instr(name,'pga')),1,'pga'
,decode(sign(instr(name,'index')),1,'index'
,decode(sign(instr(name,'cpu')),1,'cpu'
,decode(sign(instr(name,'mode')),1,'mode'
,decode(sign(instr(name,'optimizer')),1,'optimizer'
,decode(sign(instr(name,'parallel')),1,'parallel'
,decode(sign(instr(name,'rewrite')),1,'rewrite'
,decode(sign(instr(name,'statistics')),1,'statistics'
)))))))))) keyword
,name
,value
,isdefault
from v$parameter
where (
name like '%dyn%' or
name like '%pga%' or
name like '%area%' or
name like '%index%' or
name like '%cpu%' or
name like '%mode%' or
name like '%optimizer%' or
name like 'parallel%' or
name like '%rewrite%' or
name like '%statistics%'
)
order by keyword,name
/

View File

@@ -0,0 +1,7 @@
--
-- dump the most recent plan from the plan_table
--
-- usage is: @SHOWPLAN11G
--
select * from table(dbms_xplan.display('PLAN_TABLE',NULL,'ADVANCED'));

View File

@@ -0,0 +1,8 @@
--
-- dump the most recent plan in the plan_table
-- but do not include lesser used sections of the plan
--
-- usage is: @SHOWPLAN11GSHORT
--
select * from table(dbms_xplan.display('PLAN_TABLE',NULL,'ADVANCED -projection -outline -alias'));

View File

@@ -0,0 +1,60 @@
--
-- show all PK/UK/FK constraints for any table referenced by most recent query plan in the plan_table
-- note that table references may be indirect and that not all tables in a query need be used by a query plan
--
-- usage is: @SHOWPLANCONSTRAINTS11G
--
break on constraint_name skip 1 on parent_table_name
col column_name format a30
col sort_order noprint
col select_id noprint
with
plan_references as (
select id,object_owner owner,object_name table_name,replace(object_alias,'@',' @ ') object_alias
from plan_table
where object_type = 'TABLE'
and plan_id = (select max(plan_id) from plan_table)
union
select id,b.table_owner,b.table_name,replace(object_alias,'@',' @ ') object_alias
from plan_table a
,dba_indexes b
where a.object_type like 'INDEX%'
and a.object_owner = b.owner
and a.object_name = b.index_name
and a.plan_id = (select max(plan_id) from plan_table)
)
, plan_tables as (
select distinct owner,table_name
from plan_references
)
select *
from (
select a.owner,a.table_name,a.constraint_name,a.constraint_type,c.column_name,b.owner parent_child_owner,b.table_name parent_child_table_name,b.constraint_type parent_constraint_type,a.index_name,decode(a.constraint_type,'P',1,'U',2) sort_order,1 select_id
from dba_constraints a
,dba_constraints b
,dba_cons_columns c
where (a.owner,a.table_name) in (select owner,table_name from plan_tables)
and a.r_owner = b.owner(+)
and a.r_constraint_name = b.constraint_name(+)
and a.owner = c.owner
and a.constraint_name = c.constraint_name
and a.constraint_type != 'C'
and (b.owner is null and a.constraint_type in ('P','U') or (b.owner,b.table_name) in (select owner,table_name from plan_tables))
union
select a.owner,a.table_name,a.constraint_name,a.constraint_type,c.column_name,b.owner parent_child_owner,b.table_name parent_child_table_name,b.constraint_type parent_constraint_type,a.index_name,decode(a.constraint_type,'P',1,'U',2) sort_order,2 select_id
from dba_constraints a
,dba_constraints b
,dba_cons_columns c
where (a.owner,a.table_name) in (select owner,table_name from plan_tables)
and b.constraint_type in ('P','U')
and a.r_owner = b.owner
and a.r_constraint_name = b.constraint_name
and b.table_name != a.table_name
and a.owner = c.owner
and a.constraint_name = c.constraint_name
and (b.owner,b.table_name) in (select owner,table_name from plan_tables)
)
order by select_id,sort_order,owner,table_name,constraint_name,column_name
/

View File

@@ -0,0 +1,26 @@
--
-- construct count queries for tables referenced by the most recent plan in the plan_table
--
-- usage is: @SHOWPLANCOUNTQUERIES11G
--
select count_query_sqltext||decode(lead(count_query_sqltext) over (order by object_owner,object_name),null,';',' union all') sql_text
from (
select distinct object_owner,object_name,'select count(*) rowcount,'''||object_owner||''' owner,'''||object_name||''' table_name from '||object_owner||'.'||object_name count_query_sqltext
from (
select id,object_owner,object_name,replace(object_alias,'@',' @ ') object_alias
from plan_table
where object_type = 'TABLE'
and plan_id = (select max(plan_id) from plan_table)
union
select id,b.table_owner,b.table_name,replace(object_alias,'@',' @ ') object_alias
from plan_table a
,dba_indexes b
where a.object_type like 'INDEX%'
and a.object_owner = b.owner
and a.object_name = b.index_name
and a.plan_id = (select max(plan_id) from plan_table)
)
order by object_owner,object_name
)
/

View File

@@ -0,0 +1,209 @@
--
-- dumps a crude ascii art data model for the current plan in the plan_table
--
-- usage is: @SHOWPLANDATAMODEL11G
--
with
table_list as (
select b.*,chr(rownum+96) dm_key
from (
select a.*
from (
select object_owner owner,object_name table_name
from plan_table
where object_type = 'TABLE'
and plan_id = (select max(plan_id) from plan_table)
union
select b.table_owner,b.table_name
from plan_table a
,dba_indexes b
where a.object_type like 'INDEX%'
and a.object_owner = b.owner
and a.object_name = b.index_name
and a.plan_id = (select max(plan_id) from plan_table)
) a
order by a.table_name,a.owner
) b
)
, constraint_data as (
select a.owner,a.table_name,a.constraint_type,a.constraint_name,a.r_owner,a.r_constraint_name
,nvl(b.owner,a.owner) parent_owner,nvl(b.table_name,a.table_name) parent_table_name
,decode(a.constraint_type,'R',a.owner) child_owner,decode(a.constraint_type,'R',a.table_name) child_table_name
from dba_constraints a
,dba_constraints b
where a.constraint_type in ('P','R')
and (a.owner,a.table_name) in (select owner,table_name from table_list)
and a.r_owner = b.owner(+)
and a.r_constraint_name = b.constraint_name(+)
union all
select owner,table_name,'P',null,null,null,null,null,null,null
from table_list a
where not exists (
select null
from dba_constraints b
where b.owner = a.owner
and b.table_name = a.table_name
and b.constraint_type = 'P'
)
)
, table_list_plus as (
select a.owner,a.table_name,listagg(c.dm_key,',') within group (order by c.dm_key) parent_dm_key_list
from table_list a
,constraint_data b
,table_list c
where a.owner = b.child_owner
and a.table_name = b.child_table_name
and b.parent_owner = c.owner
and b.parent_table_name = c.table_name
group by a.owner,a.table_name
)
, table_level as (
select c.*,(ordinal_position)*prefix_spaces+(ordinal_position-1)*3+cumm_table_name_length-length(table_name)+1 start_position
from (
select b.*,trunc((max_total_table_name_length-total_table_name_length)/(table_count+1)) prefix_spaces
from (
select a.*,max(table_count) over () max_table_count,max(total_table_name_length) over() max_total_table_name_length
from (
select owner,table_name,max(lvlno) dm_lvl,max_dm_lvl
,sum(length(table_name)) over (partition by max(lvlno)) total_table_name_length
,count(*) over(partition by max(lvlno)) table_count
,row_number() over(partition by max(lvlno) order by table_name,owner) ordinal_position
,sum(length(table_name)) over (partition by max(lvlno) order by table_name,owner) cumm_table_name_length
from (
select level lvlno,max(level) over () max_dm_lvl,a.*
from constraint_data a
connect by r_owner = prior owner
and r_constraint_name = prior constraint_name
start with r_owner is null
)
group by owner,table_name,max_dm_lvl
) a
) b
) c
)
, table_lines as (
select a.*
from (
select table_level.*,replace(substr(sys_connect_by_path(lpad(' ',prefix_spaces,' ')||table_name,','),2),',',' ') line_text
from table_level
connect by prior dm_lvl = dm_lvl
and prior ordinal_position = ordinal_position - 1
start with ordinal_position = 1
) a
where ordinal_position = table_count
order by dm_lvl
)
, print_array as (
select x.*
,case
when exists (
select null
from table_level b2
,constraint_data c2
,table_level d2
where x.columnno = b2.start_position
and b2.owner = c2.parent_owner
and b2.table_name = c2.parent_table_name
and c2.child_owner = d2.owner
and c2.child_table_name = d2.table_name
and (
x.dm_lvl < d2.dm_lvl-1 or
x.dm_lvl = d2.dm_lvl-1 and x.rowno in (1,2)
)
) then (
select e2.dm_key
from table_level b2
,constraint_data c2
,table_level d2
,table_list e2
where x.columnno = b2.start_position
and b2.owner = c2.parent_owner
and b2.table_name = c2.parent_table_name
and c2.child_owner = d2.owner
and c2.child_table_name = d2.table_name
and (
x.dm_lvl < d2.dm_lvl-1 or
x.dm_lvl = d2.dm_lvl-1 and x.rowno in (1,2)
)
and c2.parent_owner = e2.owner
and c2.parent_table_name = e2.table_name
)
when exists (
select null
from table_level b2
,constraint_data c2
,table_level d2
where x.dm_lvl = b2.dm_lvl-1
and x.rowno in (3)
and b2.owner = c2.child_owner
and b2.table_name = c2.child_table_name
and c2.parent_owner = d2.owner
and c2.parent_table_name = d2.table_name
and (x.columnno between b2.start_position and d2.start_position or
x.columnno between d2.start_position and b2.start_position)
) then '-'
when exists (
select null
from table_level b2
,constraint_data c2
where x.columnno = b2.start_position
and b2.owner = c2.child_owner
and b2.table_name = c2.child_table_name
and x.dm_lvl = b2.dm_lvl-1
and x.rowno in (4,5)
) then (
select decode(x.rowno,4,'|','| ('||f2.parent_dm_key_list||')')
from table_level b2
,constraint_data c2
,table_list_plus f2
where x.columnno = b2.start_position
and b2.owner = c2.child_owner
and b2.table_name = c2.child_table_name
and x.dm_lvl = b2.dm_lvl-1
and x.rowno in (4,5)
and b2.owner = f2.owner
and b2.table_name = f2.table_name
)
else ' '
end cell_value
from (
select c.dm_lvl,2 rowtype,b.rowno,a.rowno columnno
from (
select rownum rowno
from dual
connect by level <= (select max(length(line_text)) from table_lines)
) a
,(
select level rowno
from dual
connect by level <= 5
) b
,table_lines c
where c.dm_lvl < c.max_dm_lvl
and a.rowno <= length(c.line_text)
) x
)
, constraint_lines as (
select *
from (
select dm_lvl,rowtype,rowno,columnno,connect_by_isleaf cbil,replace(sys_connect_by_path(cell_value,','),',') line_text
from print_array
connect by prior dm_lvl = dm_lvl
and prior rowtype = rowtype
and prior rowno = rowno
and prior columnno = columnno-1
start with columnno = 1
)
where cbil = 1
)
, data_model as (
select dm_lvl,1 rowtype,1 rowno,line_text
from table_lines
union all
select dm_lvl,rowtype,rowno,line_text
from constraint_lines
order by 1,2,3
)
select ' '||line_text data_model from data_model
/

View File

@@ -0,0 +1,36 @@
--
-- show the driving table for the most recent query plan in the plan_table
--
-- usage is: @SHOWPLANDRIVINGTABLES11G
--
set linesize 999
col driving_table format a61
col driving_table_alias format a30
col leading_hint format a300
select id
,object_owner||'.'||object_name driving_table
,driving_table_alias
,object_type
,leading_hint
from (
select substr(replace(leading_hint,')',' ')
,instr(replace(leading_hint,')',' '),' ',1,1)+1
,instr(replace(leading_hint,')',' '),' ',1,2)-instr(replace(leading_hint,')',' '),' ',1,1)-1) driving_table_alias
,leading_hint
from (
select substr(c1,1,instr(c1,')')) leading_hint
from (
select substr(other_xml,instr(other_xml,'LEADING(')) c1
from plan_table
where other_xml is not null
and plan_id = (select max(plan_id) from plan_table)
)
)
) x
,plan_table
where plan_table.object_alias = trim(replace(to_char(substr(x.driving_table_alias,1,4000)),'"'))
and plan_table.plan_id = (select max(plan_id) from plan_table)
/

View File

@@ -0,0 +1,103 @@
--
-- show filter queries for the most recent plan in the plan_table
--
-- usage is: @SHOWPLANFILTERQUERIES11G
--
with
table_list as (
select 'TABLE' plan_object_type,a.id,a.object_owner table_owner,a.object_name table_name,a.access_predicates,a.filter_predicates,a.object_alias,a.cardinality
from plan_table a
,dba_tables b
where b.owner = a.object_owner
and b.table_name = a.object_name
and a.plan_id = (select max(plan_id) from plan_table)
union all
select 'INDEX' plan_object_type,a.id,b.table_owner,b.table_name object_name,a.access_predicates,a.filter_predicates,a.object_alias,a.cardinality
from plan_table a
,dba_indexes b
where b.owner = a.object_owner
and b.index_name = a.object_name
and a.plan_id = (select max(plan_id) from plan_table)
)
--
-- given the raw data for tables, modify the predicates so that we only see predicates for constant tests, no join predicates
-- join predicates are not used in FRP analysis
-- this is a bit of a hack as I never took the COMPILER and PARSER classes in school, basically this means it is almost 100%right
--
, modified_table_list as (
select id,table_owner,table_name,object_alias,cardinality,plan_object_type
,case when
instr(replace(access_predicates,'"="'),'=') > 0 or
instr(replace(access_predicates,'">"'),'>') > 0 or
instr(replace(access_predicates,'"<"'),'<') > 0 or
instr(replace(access_predicates,'">="'),'>=') > 0 or
instr(replace(access_predicates,'"<="'),'<=') > 0 or
instr(replace(access_predicates,'"!="'),'!=') > 0 or
instr(replace(access_predicates,'"<>"'),'<>') > 0 or
instr(replace(access_predicates,'" LIKE "'),' LIKE ') > 0 or
instr(replace(access_predicates,'" BETWEEN "'),' BETWEEN ') > 0 or
instr(replace(access_predicates,'" IN ("'),' IN (') > 0 or
instr(replace(access_predicates,'" NOT LIKE "'),' NOT LIKE ') > 0 or
instr(replace(access_predicates,'" NOT BETWEEN "'),' NOT BETWEEN ') > 0 or
instr(replace(access_predicates,'" NOT IN ("'),' NOT IN (') > 0
then access_predicates
end access_predicates
,case when
instr(replace(filter_predicates,'"="'),'=') > 0 or
instr(replace(filter_predicates,'">"'),'>') > 0 or
instr(replace(filter_predicates,'"<"'),'<') > 0 or
instr(replace(filter_predicates,'">="'),'>=') > 0 or
instr(replace(filter_predicates,'"<="'),'<=') > 0 or
instr(replace(filter_predicates,'"!="'),'!=') > 0 or
instr(replace(filter_predicates,'"<>"'),'<>') > 0 or
instr(replace(filter_predicates,'" LIKE "'),' LIKE ') > 0 or
instr(replace(filter_predicates,'" BETWEEN "'),' BETWEEN ') > 0 or
instr(replace(filter_predicates,'" IN ("'),' IN (') > 0 or
instr(replace(filter_predicates,'" NOT LIKE "'),' NOT LIKE ') > 0 or
instr(replace(filter_predicates,'" NOT BETWEEN "'),' NOT BETWEEN ') > 0 or
instr(replace(filter_predicates,'" NOT IN ("'),' NOT IN (') > 0
then filter_predicates
end filter_predicates
from table_list
)
--
-- do the final massaging of the raw data
-- in particular, get the true alias for each table, get data from dba_tables, generate an actual predicate we can test with
--
, plan_info as
(
select
id
, table_owner
, table_name
, substr(object_alias,1,instr(object_alias,'@')-1) table_alias
, cardinality
, (select num_rows from dba_tables where dba_tables.owner = modified_table_list.table_owner and dba_tables.table_name = modified_table_list.table_name) num_rows
, case
when access_predicates is null and filter_predicates is null then null
when access_predicates is null and filter_predicates is not null then filter_predicates
when access_predicates is not null and filter_predicates is null then access_predicates
when access_predicates is not null and filter_predicates is not null and access_predicates != filter_predicates then access_predicates||' and '||filter_predicates
else access_predicates
end predicate
from modified_table_list
)
--
-- look for places where indexes are accessed followed by table acces by rowid
-- combine the two lines into one
--
, combined_plan_info as (
select plan_info.table_owner,plan_info.table_name,plan_info.table_alias,plan_info.num_rows
,min(plan_info.id) id
,max(plan_info.cardinality) cardinality
,listagg(plan_info.predicate,' and ') within group (order by id) predicate
from plan_info
group by plan_info.table_owner,plan_info.table_name,plan_info.table_alias,plan_info.num_rows
)
select 'select count(*) filtered_rowcount,'''||table_owner||''' table_owner,'''||table_name||''' table_name,'''||table_alias||''' table_alias from '||table_owner||'.'||table_name||' '||table_alias||decode(predicate,null,null,' where '||predicate)
||decode(lead(table_name) over (order by table_owner,table_name),null,' ;',' union all')
from combined_plan_info
order by table_owner,table_name
/

View File

@@ -0,0 +1,141 @@
--
-- generate SQL for the FRP spreadsheet from the most recent plan in the plan_table
--
-- usage is: @SHOWPLANFRPSPREADSHEETCODE11G
--
col actual_frp format 999.0
col plan_frp format 999.0
col select_id noprint
with
--
-- generates a FRP SPREADSHEET query using plan table information for an EXPLAINED query
--
--
-- THIS CODE IS DEPENDENT UPON WHAT IS IN THE PLAN TABLE
-- among other things this means that if oracle changes the contents of this table, this query may stop working
--
-- several possible flaws can prevent this code from generating an executable SQL SELECT
--
-- 1. bind variables: the corresponding select here must be modified to group on the bind column and select an round(avg(count(*))
-- 2. join predicates: if any are used along with constant tests in a plan step, they must be manaully edited out of the correspoding select here
-- 3. packaged functions: column=functioncall predicates can be dropped in which case filtered_cardinality will be affected, check it if you query has these
-- 4. outer join is not supported. These should be removed. If the case expression becomes empty use count(*).
-- 5. correlated subqueries are confusing. This is because the appear as queries with bind variables. Test like #1 but ingnore their results.
--
--
-- get raw_data from the plan_table for each table reference in the query plan
-- a table may be used more than once in which case there will be more than one row returned here
-- this is managed by using ID so that we know the plan step the table reference refers to
-- note that some plan steps may be index lookups so in this section we translate the index to its underlying table
--
table_list as (
select a.id,a.object_owner table_owner,a.object_name table_name,a.access_predicates,a.filter_predicates,a.object_alias,a.cardinality
from plan_table a
,dba_tables b
where b.owner = a.object_owner
and b.table_name = a.object_name
and a.plan_id = (select max(plan_id) from plan_table)
union all
select a.id,b.table_owner,b.table_name object_name,a.access_predicates,a.filter_predicates,a.object_alias,a.cardinality
from plan_table a
,dba_indexes b
where b.owner = a.object_owner
and b.index_name = a.object_name
and a.plan_id = (select max(plan_id) from plan_table)
)
--
-- given the raw data for tables, modify the predicates so that we only see predicates for constant tests, no join predicates
-- join predicates are not used in FRP analysis
-- this is a bit of a hack as I never took the COMPILER and PARSER classes in school, basically this means it is almost 100%right
-- what we call "close enough for jazz"
--
, modified_table_list as (
select id,table_owner,table_name,object_alias,cardinality
,case when
instr(replace(access_predicates,'"="'),'=') > 0 or
instr(replace(access_predicates,'">"'),'>') > 0 or
instr(replace(access_predicates,'"<"'),'<') > 0 or
instr(replace(access_predicates,'">="'),'>=') > 0 or
instr(replace(access_predicates,'"<="'),'<=') > 0 or
instr(replace(access_predicates,'"!="'),'!=') > 0 or
instr(replace(access_predicates,'"<>"'),'<>') > 0 or
instr(replace(access_predicates,'" LIKE "'),' LIKE ') > 0 or
instr(replace(access_predicates,'" BETWEEN "'),' BETWEEN ') > 0 or
instr(replace(access_predicates,'" IN ("'),' IN (') > 0 or
instr(replace(access_predicates,'" NOT LIKE "'),' NOT LIKE ') > 0 or
instr(replace(access_predicates,'" NOT BETWEEN "'),' NOT BETWEEN ') > 0 or
instr(replace(access_predicates,'" NOT IN ("'),' NOT IN (') > 0
then access_predicates
end access_predicates
,case when
instr(replace(filter_predicates,'"="'),'=') > 0 or
instr(replace(filter_predicates,'">"'),'>') > 0 or
instr(replace(filter_predicates,'"<"'),'<') > 0 or
instr(replace(filter_predicates,'">="'),'>=') > 0 or
instr(replace(filter_predicates,'"<="'),'<=') > 0 or
instr(replace(filter_predicates,'"!="'),'!=') > 0 or
instr(replace(filter_predicates,'"<>"'),'<>') > 0 or
instr(replace(filter_predicates,'" LIKE "'),' LIKE ') > 0 or
instr(replace(filter_predicates,'" BETWEEN "'),' BETWEEN ') > 0 or
instr(replace(filter_predicates,'" IN ("'),' IN (') > 0 or
instr(replace(filter_predicates,'" NOT LIKE "'),' NOT LIKE ') > 0 or
instr(replace(filter_predicates,'" NOT BETWEEN "'),' NOT BETWEEN ') > 0 or
instr(replace(filter_predicates,'" NOT IN ("'),' NOT IN (') > 0
then filter_predicates
end filter_predicates
from table_list
)
--
-- do the final massaging of the raw data
-- in particular, get the true alias for each table, get data from dba_tables, generate an actual predicate we can test with
--
, plan_info as
(
select
id
, table_owner
, table_name
, substr(object_alias,1,instr(object_alias,'@')-1) table_alias
, cardinality
, (select num_rows from dba_tables where dba_tables.owner = modified_table_list.table_owner and dba_tables.table_name = modified_table_list.table_name) num_rows
, case
when access_predicates is null and filter_predicates is null then null
when access_predicates is null and filter_predicates is not null then filter_predicates
when access_predicates is not null and filter_predicates is null then access_predicates
when access_predicates is not null and filter_predicates is not null and access_predicates != filter_predicates then access_predicates||' and '||filter_predicates
else access_predicates
end predicate
from modified_table_list
)
--
-- look for places where indexes are accessed followed by table acces by rowid
-- combine the two lines into one
--
, combined_plan_info as (
select plan_info.table_owner,plan_info.table_name,plan_info.table_alias,plan_info.cardinality,plan_info.num_rows
,min(plan_info.id) id
,listagg(plan_info.predicate,' and ') within group (order by id) predicate
from plan_info
group by plan_info.table_owner,plan_info.table_name,plan_info.table_alias,plan_info.cardinality,plan_info.num_rows
)
--
-- give us a SQL statement that for each table reference, both counts all rows and counts only rows that pass the filter predictes
-- then do the math needed to generate an FRP SPREADSHEET
-- this version (4) only scans each table once instead of twice like the old versions
--
select 1 select_id,'with' sqltext from dual union all
select 2 select_id,' frp_data as (' from dual union all
select 3 select_id,' select '''||lpad(id,5,' ')||''' id,'''||table_owner||''' table_owner,'''||table_name||''' table_name,'''||table_alias||''' table_alias,'||nvl(to_char(num_rows),'cast(null as number)')||' num_rows,count(*) rowcount,'||cardinality||' cardinality,'||decode(predicate,null,'cast(null as number)','count(case when '||predicate||' then 1 end)')||' filtered_cardinality from '||table_owner||'.'||table_name||' '||table_alias||' union all'
from combined_plan_info
union all
select 4 select_id,' select null,null,null,null,null,null,null,null from dual' from dual union all
select 5 select_id,' )' from dual union all
select 6 select_id,'select frp_data.*,round(frp_data.filtered_cardinality/case when frp_data.rowcount = 0 then cast(null as number) else frp_data.rowcount end*100,1) actual_frp,decode(frp_data.filtered_cardinality,null,cast(null as number),round(frp_data.cardinality/case when frp_data.num_rows = 0 then cast(null as number) else frp_data.num_rows end*100,1)) plan_frp' from dual union all
select 7 select_id,'from frp_data' from dual union all
select 8 select_id,'where id is not null' from dual union all
select 9 select_id,'order by frp_data.id' from dual union all
select 10 select_id,'/' from dual
order by 1
/

View File

@@ -0,0 +1,38 @@
--
-- show indexes for any table referenced directly or indirectly in the current plan of the plan_table
--
-- usage is: @SHOWPLANINDEXES11G
--
break on table_owner on table_name on index_owner skip 1 on index_name skip 1 on uniqueness
col column_name format a30
with
plan_references as (
select id,object_owner owner,object_name table_name,replace(object_alias,'@',' @ ') object_alias
from plan_table
where object_type = 'TABLE'
and plan_id = (select max(plan_id) from plan_table)
union
select id,b.table_owner,b.table_name,replace(object_alias,'@',' @ ') object_alias
from plan_table a
,dba_indexes b
where a.object_type like 'INDEX%'
and a.object_owner = b.owner
and a.object_name = b.index_name
and a.plan_id = (select max(plan_id) from plan_table)
)
, plan_tables as (
select distinct owner,table_name
from plan_references
)
select dba_ind_columns.column_name,dba_indexes.index_name,dba_indexes.uniqueness,dba_indexes.table_name,dba_indexes.table_owner,dba_indexes.owner index_owner
from dba_indexes
,dba_ind_columns
,plan_tables
where plan_tables.owner = dba_indexes.table_owner
and plan_tables.table_name = dba_indexes.table_name
and dba_indexes.owner = dba_ind_columns.index_owner
and dba_indexes.index_name = dba_ind_columns.index_name
order by dba_indexes.table_owner,dba_indexes.table_name,dba_indexes.owner,dba_indexes.index_name,dba_ind_columns.column_position
/

View File

@@ -0,0 +1,28 @@
--
-- get num_rows off DBA_TABLES for any table referenced by the current plan in the plan_table
--
-- usage is: @SHOWPLANNUMROWS11G
--
with
table_list as (
select object_owner owner,object_name table_name
from plan_table
where object_type = 'TABLE'
and plan_id = (select max(plan_id) from plan_table)
union
select b.table_owner,b.table_name
from plan_table a
,dba_indexes b
where a.object_type like 'INDEX%'
and a.object_owner = b.owner
and a.object_name = b.index_name
and a.plan_id = (select max(plan_id) from plan_table)
)
select num_rows,dba_tables.owner,dba_tables.table_name
from dba_tables
,table_list
where table_list.owner = dba_tables.owner
and table_list.table_name = dba_tables.table_name
order by 2,1
/

View File

@@ -0,0 +1,128 @@
--
-- show a query diagram for the current plan of the plan_table
-- uses the join tree with extended information
--
-- usage is: @SHOWPLANQUERYDIAGRAM11G
--
col query_diagram format a300
col query_name format a30
break on query_name skip 1 dup
with
plan_table_current as (
select *
from plan_table
where plan_id = (select max(plan_id) from plan_table)
)
, predicate_data as (
select nvl(query_name,'SEL$1') adjusted_query_name
,z.*
from (
select case
when table_2_alias is null then 'CONSTANT TEST'
else 'JOIN'
end expression_type
,substr(pt.object_alias,instr(object_alias,'@')+1) query_name
,y.*
from plan_table_current pt
,(
select case
when instr(predicate_expression,'.') > 0 then substr(predicate_expression,1,instr(predicate_expression,'.')-1)
else (select substr(object_alias,1,instr(object_alias,'@')-1) from plan_table_current where id = x.id and rownum = 1)
end table_1_alias
,substr(predicate_expression,instr(predicate_expression,'=')+1,instr(predicate_expression,'.',1,2)-instr(predicate_expression,'=')-1) table_2_alias
,x.*
from (
select distinct *
from (
select id,substr( ' '||p||' '
,instr(' '||p||' ',' ',1,level)+1
,instr(' '||p||' ',' ',1,level+1)-instr(' '||p||' ',' ',1,level)-1
) predicate_expression
,level rowno
,p
from (
select *
from (
select id,trim(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
p
,' ',' ')
,' ',' ')
,' ',' ')
,' ',' ')
,' ',' ')
,' ',' ')
,' ',' ')
,' ',' ')
) p
from (
select id,trim(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
p
,'"')
,' AND ',' ')
,' OR ',' ')
,' NOT ',' ')
,'(',' ')
,')',' ')
,' and ',' ')
,' and ',' ')
) p
from (
select id,access_predicates||' '||filter_predicates p
from plan_table_current
where rownum >= 1
)
)
)
where p is not null
)
connect by level <= length(p)-length(replace(p,' '))+1
)
) x
) y
where y.id = pt.id
) z
)
, constant_test as (
select distinct expression_type,table_1_alias
from predicate_data
where expression_type = 'CONSTANT TEST'
)
select t.query_name
,decode(ct,'c','c',' ')||lpad(decode(ct,'c','-',' '),(lvlno)*3,decode(ct,'c','-',' '))||table_2_alias query_diagram
from (
select query_name,table_1_alias,table_2_alias
,level lvlno
,max(level) over (partition by query_name) max_lvlno
,case when (select expression_type from constant_test where table_1_alias = x.table_2_alias) is not null then 'c' end ct
from (
select distinct adjusted_query_name query_name,table_1_alias,table_2_alias
from predicate_data
where expression_type = 'JOIN'
union all
select distinct adjusted_query_name query_name,null,table_1_alias
from predicate_data
where table_1_alias not in (select table_2_alias from predicate_data where table_2_alias is not null)
) x
connect by prior table_2_alias = table_1_alias
and prior query_name = query_name
start with table_1_alias is null
) t
/

View File

@@ -0,0 +1,23 @@
--
-- show all tables referenced by the qep
-- this include indrect references so an index reference translates to the table in this report
--
with
plan_table_current as (
select *
from plan_table
where plan_id = (select max(plan_id) from plan_table)
)
select id,object_owner,object_name,replace(object_alias,'@',' @ ') object_alias
from plan_table_current
where object_type = 'TABLE'
union
select id,b.table_owner,b.table_name,replace(object_alias,'@',' @ ') object_alias
from plan_table_current a
,dba_indexes b
where a.object_type like 'INDEX%'
and a.object_owner = b.owner
and a.object_name = b.index_name
order by 2,3,1
/

View File

@@ -0,0 +1,22 @@
--
-- show actual unique list of tables referenced by the QEP
--
with
plan_table_current as (
select *
from plan_table
where plan_id = (select max(plan_id) from plan_table)
)
select object_owner,object_name,replace(object_alias,'@',' @ ') object_alias
from plan_table_current
where object_type = 'TABLE'
union
select b.table_owner,b.table_name,replace(object_alias,'@',' @ ') object_alias
from plan_table_current a
,dba_indexes b
where a.object_type like 'INDEX%'
and a.object_owner = b.owner
and a.object_name = b.index_name
order by 1,2
/

View File

@@ -0,0 +1,124 @@
--
-- create a multi-part report on database SQL by instance
-- grouping SQL into powers of ten based on cpu consumed
-- in order to see easily the top 1% of queries that are most busy
--
set linesize 999
set pagesize 50000
set feedback 1
set trimspool on
set trimout on
set doc off
clear breaks
clear computes
set echo off
-- alter session set nls_date_format = 'dd-mon-rrrr hh24:mi:ss';
select * from v$version
/
select inst_id
,instance_name
,startup_time
,round((sysdate-startup_time),1) up_days
,round(round((sysdate-startup_time),1)*24) maximum_cache_hours
,to_char(sysdate,'dd-mon-rrrr hh24:mi:ss') right_now
from gv$instance
order by inst_id
/
--
-- show how long the database has been up, how many cpus are available, and thus the theoretical CPU available
--
select inst_id
,instance_name
,(select cpu_count_highwater from sys.v_$license) cpu_count
,round((round((sysdate-startup_time),1)*24)*(select cpu_count_highwater from sys.v_$license)) available_cpu_hours
from gv$instance
order by inst_id
/
col sql_text format a700 trunc
col sql_text clear
col sql_text format a700 trunc
col pct_total format 990
compute sum of sql_statements on inst_id
compute sum of sql_statements on report
compute sum of db_pct_total on inst_id
compute sum of db_pct_total on report
compute sum of running_consumed_cpu_hours on report
break on inst_id skip page on report
--
-- use a logarithmic scale to plot cpu consumtion of all queries in the cache
-- we can use this to zero in on the top consumers
-- notice we exclude PLSQL CALLS but not the sql inside these calls
-- this gives us the true SQL workload
--
select
inst_id
,cpu_time_log10
,sql_statements
,cpu_time_rounded,round(cpu_time) cpu_time
,round(100*ratio_to_report(cpu_time) over(partition by inst_id)) inst_pct_total
,round(100*ratio_to_report(cpu_time) over()) db_pct_total
,round(sum(cpu_time) over (partition by inst_id order by cpu_time_log10)) running_cpu_time
,round(round(sum(cpu_time) over (partition by inst_id order by cpu_time_log10))/60/60,2) running_consumed_cpu_hours
from (
select
inst_id
,trunc(log(10,mycpu_time)) cpu_time_log10
,count(*) sql_statements
,power(10,trunc(log(10,mycpu_time))) cpu_time_rounded
,sum(mycpu_time) cpu_time
from (
select inst_id,case when cpu_time <= 0 then 1 else cpu_time end/1000000 mycpu_time
from gv$sqlarea
where trim(upper(sql_text)) not like 'BEGIN%'
and trim(upper(sql_text)) not like 'DECLARE%'
and trim(upper(sql_text)) not like 'CALL%'
)
group by trunc(log(10,mycpu_time)),inst_id
) a
order by inst_id,a.cpu_time_log10
/
clear computes
col module format a30 word
col sec_per_exec format 999999990.0
--compute sum of cpu_seconds on inst_id , report
break on inst_id skip page
--
-- show use the actual SQL that exceeds some threshhold
-- these are the queries we want to concentrate on
-- configure the last AND predicate to whatever is reasonable based on the above query
--
select inst_id
,sql_id
,child_number
,trunc(cpu_time/1000000) cpu_seconds
,trunc(elapsed_time/1000000) eplapsed_seconds
,executions
,round(trunc(elapsed_time/1000000)/decode(executions,0,null,executions),1) sec_per_exec
,round((sysdate-to_date(first_load_time,'rrrr-mm-dd/hh24:mi:ss'))*24) hours_in_cache
,module
-- ,address
,hash_value
,(select 'Open' from gv$open_cursor b where b.inst_id = a.inst_id and b.address = a.address and b.hash_value = a.hash_value and rownum = 1) open
/*
,case when sql_text like '%SELECT /*+ ORDERED NO_EXPAND USE_HASH%' or sql_text like '%FROM :Q%' or instr(sql_text,'CIV_GB') > 0 or instr(sql_text,'PIV_GB') > 0 or instr(sql_text,'PIV_SSF') > 0 or instr(sql_text,'SWAP_JOIN_INPUTS') > 0 then 'Slave'
when sql_text like '%SELECT /*+ Q%' then 'Query'
else (select 'Yes' from gv$sql_plan b where b.inst_id = a.inst_id and b.address = a.address and b.hash_value = a.hash_value and b.child_number = a.child_number and b.other_tag like 'PARALLEL%' and rownum = 1)
end parallel
*/
,sql_text
from gv$sql a
where trim(upper(sql_text)) not like 'BEGIN%'
and trim(upper(sql_text)) not like 'DECLARE%'
and trim(upper(sql_text)) not like 'CALL%'
and cpu_time/1000000 >= 1000
--and cpu_time/1000000 >= 100
order by 1,4,5
/