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

View File

@@ -0,0 +1,35 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- view merging
select * from dual;
select * from table(dbms_xplan.display_cursor);
create or replace view v as select * from dual;
select * from (select * from v);
alter session set "_simple_view_merging"=false;
select * from (select * from v);
alter session set "_simple_view_merging"=true;
select * from (select /*+ NO_MERGE */ * from v);
select * from (select rownum r, v.* from v);
-- scalar subqueries, run a subquery for populating a value in a single column or a row (9i+)
select owner, count(*) from test_objects o group by owner;
-- another way (excludes nulls if any)
select u.username, (select count(*) from test_objects o where u.username = o.owner) obj_count from test_users u;
select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

View File

@@ -0,0 +1,48 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- GRANT EXECUTE ON sys.dbms_advanced_rewrite TO &user
-- there's no public synonym for this package so you should reference it by schema name
exec sys.DBMS_ADVANCED_REWRITE.DROP_REWRITE_EQUIVALENCE ('test_rewrite');
begin
sys.DBMS_ADVANCED_REWRITE.DECLARE_REWRITE_EQUIVALENCE (
'test_rewrite'
, 'select username,created from test_users u where username in (select owner from test_objects o where o.owner = u.username)'
, 'select /*+ qb_name(main) no_unnest(@subq) */ username,created from test_users u where username in (select /*+ qb_name(subq) */ owner from test_objects o where o.owner = u.username) and /* careful! */ 1=1'
, validate => true
, rewrite_mode => 'general'
);
end;
/
alter session set query_rewrite_enabled = true -- this is true by default;
alter session set query_rewrite_integrity = trusted;
-- if you see a FILTER operation (not a HASH JOIN SEMI) then the rewrite worked
select username,created from test_users u where username in (select owner from test_objects o where o.owner = u.username);
@x9a
-- an example of how to add a missing ORDER BY to a statement which assumes that GROUP BY always orders data too
-- (this is not true in 10.2+ where GROUP BY and DISTINCT operations can be done using hashing instead of sorting)
exec sys.DBMS_ADVANCED_REWRITE.DROP_REWRITE_EQUIVALENCE ('test_rewrite_order');
begin
sys.DBMS_ADVANCED_REWRITE.DECLARE_REWRITE_EQUIVALENCE (
'test_rewrite_order'
, 'select owner,count(*) from test_objects group by owner'
, 'select * from (select owner,count(*) from test_objects group by owner order by owner)'
, validate => true
, rewrite_mode => 'text_match'
);
end;
/
select owner,count(*) from test_objects group by owner;
@x9a

View File

@@ -0,0 +1,133 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
DROP TABLE badly_correlated1;
DROP TABLE badly_correlated2;
CREATE TABLE badly_correlated1 (id, a, b, c, d, e, f, g, h, val) AS (
SELECT rownum id, v.* FROM (
SELECT
mod(rownum, 100000) a
, mod(rownum, 100000) b
, mod(rownum, 100000) c
, mod(rownum, 100000) d
, mod(rownum, 100000) e
, mod(rownum, 100000) f
, mod(rownum, 100000) g
, mod(rownum, 100000) h
, lpad('x',100,'x')
FROM
dual CONNECT BY LEVEL <= 100000
UNION ALL
SELECT
90 a
, 91 b
, 92 c
, 93 d
, 94 e
, 95 f
, 96 g
, 97 h
, lpad('y',100,'y')
FROM
dual CONNECT BY LEVEL <= 100000
) v
)
/
CREATE TABLE badly_correlated2 AS SELECT * FROM badly_correlated1;
ALTER TABLE badly_correlated1 MODIFY id PRIMARY KEY;
ALTER TABLE badly_correlated2 MODIFY id PRIMARY KEY;
CREATE INDEX idx1_badly_correlated1 ON badly_correlated1 (a,b,c,d,e,f,g);
CREATE INDEX idx1_badly_correlated2 ON badly_correlated2 (a,b,c,d,e,f,g);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'BADLY_CORRELATED1', method_opt=>'FOR TABLE', cascade=>true);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'BADLY_CORRELATED2', method_opt=>'FOR TABLE', cascade=>true);
select /*+ opt_param('_optimizer_use_feedback', 'false') */
*
from
badly_correlated1 t1
, badly_correlated2 t2
where
t1.id = t2.id
and t1.a = 90
and t1.b = 91
and t1.c = 92
and t1.d = 93
and t1.e = 94
and t1.f = 95
and t1.g = 96
and t1.h = 97
and t2.val like 'xy%'
/
@x
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'BADLY_CORRELATED1', method_opt=>'FOR TABLE FOR ALL COLUMNS SIZE 254', cascade=>true);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'BADLY_CORRELATED2', method_opt=>'FOR TABLE FOR ALL COLUMNS SIZE 254', cascade=>true);
select /*+ opt_param('_optimizer_use_feedback', 'false') */
*
from
badly_correlated1 t1
, badly_correlated2 t2
where
t1.id = t2.id
and t1.a = 90
and t1.b = 91
and t1.c = 92
and t1.d = 93
and t1.e = 94
and t1.f = 95
and t1.g = 96
and t1.h = 97
and t2.val like 'xy%'
/
@x
-- create extended stats
select
dbms_stats.create_extended_stats(
ownname => user
, tabname=>'BADLY_CORRELATED1'
, extension=>'(a,b,c,d,e,f,g,h)'
)
from dual
/
select
dbms_stats.create_extended_stats(
ownname => user
, tabname=>'BADLY_CORRELATED2'
, extension=>'(a,b,c,d,e,f,g,h)'
)
from dual
/
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'BADLY_CORRELATED1', method_opt=>'FOR TABLE FOR ALL COLUMNS SIZE 254', cascade=>true);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'BADLY_CORRELATED2', method_opt=>'FOR TABLE FOR ALL COLUMNS SIZE 254', cascade=>true);
select /*+ opt_param('_optimizer_use_feedback', 'false') */
*
from
badly_correlated1 t1
, badly_correlated2 t2
where
t1.id = t2.id
and t1.a = 90
and t1.b = 91
and t1.c = 92
and t1.d = 93
and t1.e = 94
and t1.f = 95
and t1.g = 96
and t1.h = 97
and t2.val like 'xy%'
/
@x

View File

@@ -0,0 +1,126 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
--------------------------------------------------------------------------------
--
-- File name: demos/bind_peeking_nested_loops.sql
-- Purpose: this script demos how a "wrong" bind variable value
-- can cause an execution plan to be compiled which is
-- very inefficient for the next execution with different bind variable
-- values (with large number of matching rows)
-- the second execution of the query takes very long time to complete
-- despite adaptive bind variable peeking, which would kick in during the
-- next (3rd) execution
--
-- This problem happens even on Oracle 11.2 despite adaptive bind peeking
-- and cardinality feedback (due to design, not a bug)
--
-- Author: Tanel Poder (tanel@e2sn.com)
-- Copyright: (c) http://tech.e2sn.com
--
--------------------------------------------------------------------------------
alter session set optimizer_use_sql_plan_baselines = false;
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;
DROP TABLE t5;
CREATE TABLE t1 AS SELECT * FROM dba_objects WHERE rownum <= 50000;
CREATE TABLE t2 AS SELECT * FROM dba_objects WHERE rownum <= 10000;
CREATE TABLE t3 AS SELECT * FROM dba_objects WHERE rownum <= 10000;
CREATE TABLE t4 AS SELECT * FROM dba_objects WHERE rownum <= 10000;
CREATE TABLE t5 AS SELECT * FROM dba_objects WHERE rownum <= 10000;
CREATE INDEX i1 ON t1(owner);
CREATE INDEX i2 ON t2(owner);
CREATE INDEX i3 ON t3(owner);
CREATE INDEX i4 ON t4(owner);
CREATE INDEX i5 ON t5(owner);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T1',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T2',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T3',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T4',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T5',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T1',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T2',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T3',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T4',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T5',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- this hack might be needed to "help" this problem to show up sometimes:
-- ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ=10;
VAR v1 VARCHAR2(100)
VAR v2 VARCHAR2(100)
VAR v3 VARCHAR2(100)
VAR v4 VARCHAR2(100)
VAR v5 VARCHAR2(100)
EXEC :v1:='SCOTT'
EXEC :v2:='SCOTT'
EXEC :v3:='SCOTT'
EXEC :v4:='SCOTT'
EXEC :v5:='SCOTT'
SET TIMING ON
PROMPT Running query first time, this should be fast (and should use nested loops execution plan)
SELECT
MIN(t1.created), MAX(t1.created)
FROM
t1
, t2
, t3
, t4
, t5
WHERE
t1.object_id = t2.object_id
AND t2.object_id = t3.object_id
AND t3.object_id = t4.object_id
AND t4.object_id = t5.object_id
AND t1.owner = :v1
AND t2.owner = :v2
AND t3.owner = :v3
AND t4.owner = :v4
AND t5.owner = :v5
/
SET TIMING OFF
--SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null,'ALLSTATS LAST ADVANCED'));
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null));
EXEC :v1:='SYS'
EXEC :v2:='SYS'
EXEC :v3:='SYS'
EXEC :v4:='SYS'
EXEC :v5:='SYS'
SET TIMING ON
PROMPT Now running the same query with different bind variables (this query should take very long time)
SELECT
MIN(t1.created), MAX(t1.created)
FROM
t1
, t2
, t3
, t4
, t5
WHERE
t1.object_id = t2.object_id
AND t2.object_id = t3.object_id
AND t3.object_id = t4.object_id
AND t4.object_id = t5.object_id
AND t1.owner = :v1
AND t2.owner = :v2
AND t3.owner = :v3
AND t4.owner = :v4
AND t5.owner = :v5
/

View File

@@ -0,0 +1,87 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
--------------------------------------------------------------------------------
--
-- File name: demos/bind_peeking_nested_loops.sql
-- Purpose: this script demos how a "wrong" bind variable value
-- can cause an execution plan to be compiled which is
-- very inefficient for the next execution with different bind variable
-- values (with large number of matching rows)
-- the second execution of the query takes very long time to complete
-- despite adaptive bind variable peeking, which would kick in during the
-- next (3rd) execution
--
-- This problem happens even on Oracle 11.2 despite adaptive bind peeking
-- and cardinality feedback (due design, not a bug)
--
-- Author: Tanel Poder (tanel@e2sn.com)
-- Copyright: (c) http://tech.e2sn.com
--
--------------------------------------------------------------------------------
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
CREATE TABLE t1 AS SELECT * FROM dba_objects;
CREATE TABLE t2 AS SELECT * FROM dba_objects;
CREATE TABLE t3 AS SELECT * FROM dba_objects;
CREATE INDEX i1 ON t1(owner);
CREATE INDEX i2 ON t2(owner);
CREATE INDEX i3 ON t3(owner);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T1',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T2',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T3',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ=10;
VAR v VARCHAR2(100)
EXEC :v:='SYS'
SET TIMING ON
PROMPT Running query first time, this should be fast (and should use nested loops execution plan)
SELECT
MIN(t1.created), MAX(t1.created)
FROM
t1
, t2
, t3
WHERE
t1.object_id = t2.object_id
AND t2.object_id = t3.object_id
AND t1.owner = :v
AND t2.owner = :v
AND t3.owner = :v
/
SET TIMING OFF
--SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null,'ALLSTATS LAST ADVANCED'));
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null));
EXEC :v:='SCOTT'
SET TIMING ON
PROMPT Now running the same query with different bind variables (this query should take very long time)
SELECT
MIN(t1.created), MAX(t1.created)
FROM
t1
, t2
, t3
WHERE
t1.object_id = t2.object_id
AND t2.object_id = t3.object_id
AND t1.owner = :v
AND t2.owner = :v
AND t3.owner = :v
/

View File

@@ -0,0 +1,87 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
--------------------------------------------------------------------------------
--
-- File name: demos/bind_peeking_nested_loops.sql
-- Purpose: this script demos how a "wrong" bind variable value
-- can cause an execution plan to be compiled which is
-- very inefficient for the next execution with different bind variable
-- values (with large number of matching rows)
-- the second execution of the query takes very long time to complete
-- despite adaptive bind variable peeking, which would kick in during the
-- next (3rd) execution
--
-- This problem happens even on Oracle 11.2 despite adaptive bind peeking
-- and cardinality feedback (due design, not a bug)
--
-- Author: Tanel Poder (tanel@e2sn.com)
-- Copyright: (c) http://tech.e2sn.com
--
--------------------------------------------------------------------------------
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
CREATE TABLE t1 AS SELECT * FROM dba_objects;
CREATE TABLE t2 AS SELECT * FROM dba_objects;
CREATE TABLE t3 AS SELECT * FROM dba_objects;
CREATE INDEX i1 ON t1(owner);
CREATE INDEX i2 ON t2(owner);
CREATE INDEX i3 ON t3(owner);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T1',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T2',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T3',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ=10;
VAR v VARCHAR2(100)
EXEC :v:='SCOTT'
SET TIMING ON
PROMPT Running query first time, this should be fast (and should use nested loops execution plan)
SELECT
MIN(t1.created), MAX(t1.created)
FROM
t1
, t2
, t3
WHERE
t1.object_id = t2.object_id
AND t2.object_id = t3.object_id
AND t1.owner = :v
AND t2.owner = :v
AND t3.owner = :v
/
SET TIMING OFF
--SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null,'ALLSTATS LAST ADVANCED'));
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null));
EXEC :v:='SYS'
SET TIMING ON
PROMPT Now running the same query with different bind variables (this query should take very long time)
SELECT
MIN(t1.created), MAX(t1.created)
FROM
t1
, t2
, t3
WHERE
t1.object_id = t2.object_id
AND t2.object_id = t3.object_id
AND t1.owner = :v
AND t2.owner = :v
AND t3.owner = :v
/

View File

@@ -0,0 +1,98 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
--------------------------------------------------------------------------------
--
-- File name: demos/bind_peeking_nested_loops.sql
-- Purpose: this script demos how a "wrong" bind variable value
-- can cause an execution plan to be compiled which is
-- very inefficient for the next execution with different bind variable
-- values (with large number of matching rows)
-- the second execution of the query takes very long time to complete
-- despite adaptive bind variable peeking, which would kick in during the
-- next (3rd) execution
--
-- This problem happens even on Oracle 11.2 despite adaptive bind peeking
-- and cardinality feedback (due to design, not a bug)
--
-- Author: Tanel Poder (tanel@e2sn.com)
-- Copyright: (c) http://tech.e2sn.com
--
--------------------------------------------------------------------------------
alter session set optimizer_use_sql_plan_baselines = false;
DROP TABLE t_bp1;
DROP TABLE t_bp2;
DROP TABLE t_bp3;
DROP TABLE t_bp4;
DROP TABLE t_bp5;
CREATE TABLE t_bp1 AS SELECT * FROM dba_objects WHERE rownum <= 50000;
CREATE TABLE t_bp2 AS SELECT * FROM dba_objects WHERE rownum <= 10000;
CREATE TABLE t_bp3 AS SELECT * FROM dba_objects WHERE rownum <= 10000;
CREATE TABLE t_bp4 AS SELECT * FROM dba_objects WHERE rownum <= 10000;
CREATE TABLE t_bp5 AS SELECT * FROM dba_objects WHERE rownum <= 10000;
CREATE INDEX i_bp1 ON t_bp1(owner);
CREATE INDEX i_bp2 ON t_bp2(owner);
CREATE INDEX i_bp3 ON t_bp3(owner);
CREATE INDEX i_bp4 ON t_bp4(owner);
CREATE INDEX i_bp5 ON t_bp5(owner);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T_BP1',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T_BP2',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T_BP3',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T_BP4',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T_BP5',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 254');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T1',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T2',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T3',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T4',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T5',cascade=>TRUE, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1');
-- this hack might be needed to "help" this problem to show up sometimes:
-- ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ=10;
CREATE OR REPLACE PROCEDURE test_bp (num_loops IN NUMBER, sleep IN NUMBER
, v1 IN VARCHAR2, v2 IN VARCHAR2, v3 IN VARCHAR2, v4 IN VARCHAR2, v5 IN VARCHAR2)
AS
r1 DATE;
r2 DATE;
s NUMBER;
BEGIN
FOR i IN 1..num_loops LOOP
SELECT /*+ opt_param('_optimizer_use_feedback', 'false') */
MIN(t_bp1.created), MAX(t_bp5.created) INTO r1, r2
FROM
t_bp1
, t_bp2
, t_bp3
, t_bp4
, t_bp5
WHERE
t_bp1.object_id = t_bp2.object_id
AND t_bp2.object_id = t_bp3.object_id
AND t_bp3.object_id = t_bp4.object_id
AND t_bp4.object_id = t_bp5.object_id
AND t_bp1.owner = v1
AND t_bp2.owner = v2
AND t_bp3.owner = v3
AND t_bp4.owner = v4
AND t_bp5.owner = v5;
s := s + (r2 - r1); -- dummy calculation
IF sleep > 0 THEN DBMS_LOCK.SLEEP(sleep); END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE(TO_CHAR(s));
END;
/
PROMPT Running query first time, this should be fast (and should use nested loops execution plan)
--SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null));
SET TIMING ON
PROMPT Now running the same query with different bind variables (this query should take very long time)

View File

@@ -0,0 +1,111 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
--------------------------------------------------------------------------------
--
-- File name: 02_choosing_join_order.sql
--
-- Purpose: Advanced Oracle SQL Tuning demo script
-- Author: Tanel Poder
-- Copyright: (c) http://www.tanelpoder.com
--
-- Usage: You can run the query against Oracle's sample schemas (SH)
-- The optimizer stats have to be updated to cause trouble.
-- See the commented out code below
--
--------------------------------------------------------------------------------
-- in Oracle 11gR2, set the cardinality feedback option to false for demo stability purposes
-- alter session set "_optimizer_use_feedback"=false;
--
-- Set statistics_level = all for measuring optimizer misestimate (or use V$SQL_MONITOR):
-- alter session set statistics_level = all;
--
-- Cause trouble for the optimizer:
-- EXEC DBMS_STATS.SET_TABLE_STATS('SH','CUSTOMERS', NUMROWS=>1, NUMBLKS=>1, NO_INVALIDATE=>FALSE);
SELECT /*+ MONITOR */
ch.channel_desc
, co.country_iso_code co
, cu.cust_city
, p.prod_category
, sum(s.quantity_sold)
, sum(s.amount_sold)
FROM
sh.sales s
, sh.customers cu
, sh.countries co
, sh.products p
, sh.channels ch
WHERE
-- join
s.cust_id = cu.cust_id
AND cu.country_id = co.country_id
AND s.prod_id = p.prod_id
AND s.channel_id = ch.channel_id
-- filter
AND ch.channel_class = 'Direct'
AND co.country_iso_code = 'US'
AND p.prod_category = 'Electronics'
GROUP BY
ch.channel_desc
, co.country_iso_code
, cu.cust_city
, p.prod_category
/
--------------------------------------------------------------------------------------------------------
-- SQL Profiles (require Tuning + Diag Pack):
--------------------------------------------------------------------------------------------------------
--
-- VAR sql_fulltext CLOB
-- EXEC SELECT sql_fulltext INTO :sql_fulltext FROM v$sql WHERE sql_id = '1ka5g0kh4h6pc' AND rownum = 1;
--
-- Example 1: Set Join order:
-- EXEC DBMS_SQLTUNE.IMPORT_SQL_PROFILE(sql_text=>:sql_fulltext, profile=>sys.sqlprof_attr('LEADING(@"SEL$1" "CO"@"SEL$1" "CH"@"SEL$1" "CU"@"SEL$1" "S"@"SEL$1" "P"@"SEL$1")'), name=> 'MANUAL_PROFILE_1ka5g0kh4h6pc');
--
-- Example 2: Adjust cardinality:
-- EXEC DBMS_SQLTUNE.IMPORT_SQL_PROFILE(sql_text=>:sql_fulltext, profile=>sys.sqlprof_attr('CARDINALITY(@"SEL$1" "CU"@"SEL$1" 100000)'), name=> 'MANUAL_PROFILE_1ka5g0kh4h6pc');
--
-- Example 3: Set multiple hints:
-- DECLARE
-- hints sys.sqlprof_attr := sys.sqlprof_attr(
-- ('LEADING(@"SEL$1" "CO"@"SEL$1" "CH"@"SEL$1"')
-- , ('CARDINALITY(@"SEL$1" "CU"@"SEL$1" 100000)')
-- );
-- BEGIN
-- DBMS_SQLTUNE.IMPORT_SQL_PROFILE(sql_text=>:sql_fulltext, profile=> hints, name=> 'MANUAL_PROFILE_1ka5g0kh4h6pc');
-- END;
-- /
--
-- Drop the profile:
-- EXEC DBMS_SQLTUNE.DROP_SQL_PROFILE('MANUAL_PROFILE_1ka5g0kh4h6pc');
--
--
--------------------------------------------------------------------------------------------------------
-- SQL Plan Baselines - DBMS_SPM in EE licenses - see http://jonathanlewis.wordpress.com/2011/01/12/fake-baselines/
--------------------------------------------------------------------------------------------------------
-- bad_sqlid = 1ka5g0kh4h6pc
-- good_sqlid = 1fzf3vqv0f49q
-- 1) Manually run the query with hints, params, etc to get the plan you want (the good query)
--
-- 2) Create a disabled plan baseline for the "bad query":
-- VAR x NUMBER
-- EXEC :x:= DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE('&bad_sqlid', enabled=>'NO');
--
-- 3) SELECT sql_handle FROM dba_sql_plan_baselines WHERE sql_text = '<your sql_text>';
--
-- 4) Associate the "good query" plan with the "bad query" SQL plan baseline:
-- DEF good_sql_id = 1fzf3vqv0f49q
-- DEF good_plan_hash_value = 2863714589
-- DEF sql_handle_for_original = SQL_4b3ef772af37954d
-- VAR x NUMBER
--
-- exec :x := dbms_spm.load_plans_from_cursor_cache( -
-- sql_id => '&good_sql_id', -
-- plan_hash_value => &good_plan_hash_value, -
-- sql_handle => '&sql_handle_for_original');
--

View File

@@ -0,0 +1,25 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- TODO: not working yet
-- LEADING hint sets the order properly but not the ORDERED hint
drop table t1;
drop table t2;
create table t1 as select * from all_objects;
create table t2 as select * from all_objects;
create index i1 on t2(object_id);
exec dbms_stats.gather_table_stats(user,'T1');
exec dbms_stats.gather_table_stats(user,'T2');
-- ordered hint "ignored" starting from 11.2.0.1 thanks to distinct aggregation transformation
select /*+ ORDERED */ t1.owner, count(distinct t2.object_type) from t2, t1 where t1.object_id = t2.object_id group by t1.owner;
@x
select /*+ ORDERED NO_TRANSFORM_DISTINCT_AGG */ t1.owner, count(distinct t2.object_type) from t2, t1 where t1.object_id = t2.object_id group by t1.owner;
@x

View File

@@ -0,0 +1,73 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
set echo on
select
t.owner, t.created, i.last_ddl_time
from
test_objects t
, indexed_objects i
where
t.object_id = i.object_id
and t.owner = 'SH'
and t.object_name like 'S%'
/
@xall
select /*+ LEADING(t,i) USE_NL(i) */
t.owner, t.created, i.last_ddl_time
from
test_objects t
, indexed_objects i
where
t.object_id = i.object_id
and t.owner = 'SH'
and t.object_name like 'S%'
/
@xall
select /*+ LEADING(t,i) USE_NL(i) NO_NLJ_PREFETCH(i) */
t.owner, t.created, i.last_ddl_time
from
test_objects t
, indexed_objects i
where
t.object_id = i.object_id
and t.owner = 'SH'
and t.object_name like 'S%'
/
@xall
select /*+ LEADING(t,i) USE_NL(i) NO_NLJ_BATCHING(i) */
t.owner, t.created, i.last_ddl_time
from
test_objects t
, indexed_objects i
where
t.object_id = i.object_id
and t.owner = 'SH'
and t.object_name like 'S%'
/
@xall
select /*+ LEADING(t,i) USE_NL(i) NO_NLJ_PREFETCH(t) NO_NLJ_PREFETCH(i) NO_NLJ_BATCHING(t) NO_NLJ_BATCHING(i) */
t.owner, t.created, i.last_ddl_time
from
test_objects t
, indexed_objects i
where
t.object_id = i.object_id
and t.owner = 'SH'
and t.object_name like 'S%'
/
@xall
set echo off

25
tpt/ast/02_leading_sq.sql Normal file
View File

@@ -0,0 +1,25 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
select
/*+
no_unnest(@my_sub)
leading (@my_sub emp_inner@my_sub)
use_merge (@my_sub dept_inner@my_sub)
*/
*
from
scott.emp emp_outer
where
emp_outer.deptno in (
select /*+ qb_name(my_sub) */
dept_inner.deptno
from
scott.dept dept_inner
, scott.emp emp_inner
where
dept_inner.dname like 'S%'
and emp_inner.ename = dept_inner.dname
and dept_inner.deptno = emp_outer.deptno
)
/

View File

@@ -0,0 +1,176 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- Advanced Oracle SQL Tuning
-- when testing purposes on 11g+
ALTER SESSION SET "_optimizer_use_feedback"=FALSE;
--exec dbms_outln.drop_unused;
exec dbms_outln.drop_by_cat('TEMP_SWAP_OUTLINE');
exec dbms_outln.drop_by_cat('TEMP_SWAP_OUTLINE_BAD');
exec dbms_outln.drop_by_cat('TEMP_SWAP_OUTLINE_GOOD');
-- this command will drop all default outlines!!!
exec dbms_outln.drop_by_cat('DEFAULT');
delete from ol$;
delete from ol$hints;
delete from ol$nodes;
COMMIT;
ALTER SYSTEM FLUSH SHARED_POOL;
-- bad original query
SELECT
ch.channel_desc
, co.country_iso_code co
, cu.cust_city
, p.prod_category
, sum(s.quantity_sold)
, sum(s.amount_sold)
FROM
sh.sales s
, sh.customers cu
, sh.countries co
, sh.products p
, sh.channels ch
WHERE
-- join
s.cust_id = cu.cust_id
AND cu.country_id = co.country_id
AND s.prod_id = p.prod_id
AND s.channel_id = ch.channel_id
-- filter
AND ch.channel_class = 'Direct'
AND co.country_iso_code = 'US'
AND p.prod_category = 'Electronics'
GROUP BY
ch.channel_desc
, co.country_iso_code
, cu.cust_city
, p.prod_category
/
/
@hash
-- manually tuned query
SELECT /*+ CARDINALITY(cu 55500) CARDINALITY(s 918000) */
ch.channel_desc
, co.country_iso_code co
, cu.cust_city
, p.prod_category
, sum(s.quantity_sold)
, sum(s.amount_sold)
FROM
sh.sales s
, sh.customers cu
, sh.countries co
, sh.products p
, sh.channels ch
WHERE
-- join
s.cust_id = cu.cust_id
AND cu.country_id = co.country_id
AND s.prod_id = p.prod_id
AND s.channel_id = ch.channel_id
-- filter
AND ch.channel_class = 'Direct'
AND co.country_iso_code = 'US'
AND p.prod_category = 'Electronics'
GROUP BY
ch.channel_desc
, co.country_iso_code
, cu.cust_city
, p.prod_category
/
/
@hash
-- orig: 2689079980 1ka5g0kh4h6pc 0
-- tuned: 3053916470 1fzf3vqv0f49q 0
-- workaround bug: Bug 5454975 : ORA-3113 WHEN EXECUTING DBMS_OUTLN.CREATE_OUTLINE
ALTER SESSION SET create_stored_outlines = TRUE;
-- make sure you use right SQL hash values and child cursor numbers here!
EXEC DBMS_OUTLN.CREATE_OUTLINE(2689079980, 0, 'TEMP_SWAP_OUTLINE_BAD');
EXEC DBMS_OUTLN.CREATE_OUTLINE(3053916470, 0, 'TEMP_SWAP_OUTLINE_GOOD');
ALTER SESSION SET create_stored_outlines = FALSE;
COL outline_name_bad NEW_VALUE outline_name_bad
COL outline_name_good NEW_VALUE outline_name_good
-- get outline names
SELECT category,name outline_name_bad,owner,signature,enabled,timestamp,version FROM dba_outlines WHERE category = 'TEMP_SWAP_OUTLINE_BAD';
SELECT category,name outline_name_good,owner,signature,enabled,timestamp,version FROM dba_outlines WHERE category = 'TEMP_SWAP_OUTLINE_GOOD';
-- change the outlines to the same category for modification
ALTER OUTLINE &outline_name_bad CHANGE CATEGORY TO temp_swap_outline;
ALTER OUTLINE &outline_name_good CHANGE CATEGORY TO temp_swap_outline;
CREATE PRIVATE OUTLINE bad FROM &outline_name_bad;
CREATE PRIVATE OUTLINE good FROM &outline_name_good;
-- these ol$ and ol$hints tables are actually just GTTs (private to your session - private outlines)
-- do NOT modify the real ol$ and ol$hints tables in OUTLN schema directly!!!
SAVEPOINT before_ol_update;
UPDATE ol$ SET hintcount=(SELECT hintcount FROM ol$ WHERE ol_name='GOOD') where ol_name='BAD';
DELETE FROM ol$ WHERE ol_name='GOOD';
DELETE FROM ol$hints WHERE ol_name='BAD';
UPDATE ol$hints SET ol_name='BAD' where ol_name='GOOD';
COMMIT;
-- this just invalidate outline
EXEC DBMS_OUTLN_EDIT.REFRESH_PRIVATE_OUTLINE('BAD');
ALTER SESSION SET use_private_outlines = TRUE;
-- run the original query again now - it should show "outline "BAD" used for this statement
-- ...
ALTER SESSION SET use_private_outlines = FALSE;
-- now publish the outline for use by others:
CREATE OR REPLACE OUTLINE &outline_name_bad FROM PRIVATE bad FOR CATEGORY temp_swap_outline;
ALTER SESSION SET use_stored_outlines = temp_swap_outline;
-- run the query again, it should show the original production outline used, but with the new plan ...
-- change the outline to DEFAULT category so that any session with use_stored_outlines = TRUE would use it
ALTER OUTLINE &outline_name_bad CHANGE CATEGORY TO "DEFAULT";
ALTER SESSION SET use_stored_outlines = TRUE;
-- optional...
ALTER OUTLINE &outline_name_bad RENAME TO outline_1ka5g0kh4h6pc;
SELECT
ch.channel_desc
, co.country_iso_code co
, cu.cust_city
, p.prod_category
, sum(s.quantity_sold)
, sum(s.amount_sold)
FROM
sh.sales s
, sh.customers cu
, sh.countries co
, sh.products p
, sh.channels ch
WHERE
-- join
s.cust_id = cu.cust_id
AND cu.country_id = co.country_id
AND s.prod_id = p.prod_id
AND s.channel_id = ch.channel_id
-- filter
AND ch.channel_class = 'Direct'
AND co.country_iso_code = 'US'
AND p.prod_category = 'Electronics'
GROUP BY
ch.channel_desc
, co.country_iso_code
, cu.cust_city
, p.prod_category
/
@x

View File

@@ -0,0 +1,23 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
drop table qt_test;
create table qt_test (
id number primary key
, name varchar2(100)
)
/
insert into qt_test select rownum, lpad('x',100,'x') from dual connect by level <=10000;
exec dbms_stats.gather_table_stats(user,'QT_TEST');
select count(name) from qt_test;
@x
alter table qt_test modify name not null;
select count(name) from qt_test;
@x

View File

@@ -0,0 +1,34 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
--------------------------------------------------------------------------------------------------------
-- SQL Plan Baselines - DBMS_SPM in EE licenses - see http://jonathanlewis.wordpress.com/2011/01/12/fake-baselines/
--------------------------------------------------------------------------------------------------------
-- bad_sqlid = 1ka5g0kh4h6pc
-- good_sqlid = 1fzf3vqv0f49q
-- 1) Make sure your "bad query" is in library cache
-- 2) Manually optimize the query with hints, params, etc to get the plan you want (the "good query")
-- 3) Create a disabled plan baseline for the "bad query":
VAR x NUMBER
EXEC :x:= DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE('&bad_sqlid', enabled=>'NO');
-- 4) Find the SQL handle of your "bad" query:
SELECT sql_handle FROM dba_sql_plan_baselines WHERE sql_text = '<your sql_text>';
-- 5) Associate the "good query" plan with the "bad query" SQL plan baseline:
DEF good_sql_id = 1fzf3vqv0f49q
DEF good_plan_hash_value = 2863714589
DEF sql_handle_for_original = SQL_4b3ef772af37954d
VAR x NUMBER
exec :x := dbms_spm.load_plans_from_cursor_cache( -
sql_id => '&good_sql_id', -
plan_hash_value => &good_plan_hash_value, -
sql_handle => '&sql_handle_for_original');

View File

@@ -0,0 +1,44 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- use the @ast/02_choosing_join_order.sql script to run the demo query
--------------------------------------------------------------------------------------------------------
-- SQL Profiles (require Tuning + Diag Pack):
--------------------------------------------------------------------------------------------------------
-- Drop the profile:
-- EXEC DBMS_SQLTUNE.DROP_SQL_PROFILE('MANUAL_PROFILE_1ka5g0kh4h6pc');
VAR sql_fulltext CLOB
EXEC SELECT sql_fulltext INTO :sql_fulltext FROM v$sql WHERE sql_id = '1ka5g0kh4h6pc' AND rownum = 1;
-- Example 1: Set Join order:
EXEC DBMS_SQLTUNE.IMPORT_SQL_PROFILE(sql_text=>:sql_fulltext, profile=>sys.sqlprof_attr('LEADING(@"SEL$1" "CO"@"SEL$1" "CH"@"SEL$1" "CU"@"SEL$1" "S"@"SEL$1" "P"@"SEL$1")'), name=> 'MANUAL_PROFILE_1ka5g0kh4h6pc');
-- Example 2: Adjust cardinality:
EXEC DBMS_SQLTUNE.IMPORT_SQL_PROFILE(sql_text=>:sql_fulltext, profile=>sys.sqlprof_attr('OPT_ESTIMATE(@"SEL$1", TABLE, "CU"@"SEL$1", SCALE_ROWS=100000)'), name=> 'MANUAL_PROFILE_1ka5g0kh4h6pc');
-- Example 3: Set multiple hints:
DECLARE
hints sys.sqlprof_attr := sys.sqlprof_attr(
('LEADING(@"SEL$1" "CO"@"SEL$1" "CH"@"SEL$1")')
, ('OPT_ESTIMATE(@"SEL$1", TABLE, "CU"@"SEL$1", SCALE_ROWS=100000)')
);
BEGIN
DBMS_SQLTUNE.IMPORT_SQL_PROFILE(sql_text=>:sql_fulltext, profile=> hints, name=> 'MANUAL_PROFILE_1ka5g0kh4h6pc');
END;
/
-- Example 4: SwingBench TPCDS-Like Query 31 skip scan issue (force match)
-- alternative option would be to use opt_param('_optimizer_skip_scan_enabled','false')
DECLARE
hints sys.sqlprof_attr := sys.sqlprof_attr(
('NO_INDEX_SS(@"SEL$26CA4453" "STORE_SALES"@"SEL$1")')
, ('NO_INDEX_SS(@"SEL$2C2C13D8" "WEB_SALES"@"SEL$2")')
);
BEGIN
DBMS_SQLTUNE.IMPORT_SQL_PROFILE(sql_text=>:sql_fulltext, profile=> hints, name=> 'QUERY31_DISABLE_SKIP_SCAN', force_match=> TRUE);
END;
/

View File

@@ -0,0 +1,36 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- setting the 11.2 cardinality feedback option to false for demo stability purposes
exec execute immediate 'alter session set "_optimizer_use_feedback"=false'; exception when others then null;
SELECT /*+ star_transformation */
ch.channel_desc
, co.country_iso_code co
, cu.cust_city
, p.prod_category
, sum(s.quantity_sold)
, sum(s.amount_sold)
FROM
sh.sales s
, sh.customers cu
, sh.countries co
, sh.products p
, sh.channels ch
WHERE
-- join
s.cust_id = cu.cust_id
AND cu.country_id = co.country_id
AND s.prod_id = p.prod_id
AND s.channel_id = ch.channel_id
-- filter
AND ch.channel_class = 'Direct'
AND co.country_iso_code = 'US'
AND p.prod_category = 'Electronics'
GROUP BY
ch.channel_desc
, co.country_iso_code
, cu.cust_city
, p.prod_category
/

View File

@@ -0,0 +1,46 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
DROP TABLE cons_demo;
CREATE TABLE cons_demo (owner varchar2(100), object_name varchar2(128));
INSERT /*+ APPEND */ INTO cons_demo SELECT owner, object_name FROM dba_objects;
COMMIT;
SELECT COUNT(*) FROM cons_demo;
@x
CREATE INDEX idx1_cons_demo ON cons_demo(owner);
SELECT COUNT(*) FROM cons_demo;
@x
SELECT /*+ INDEX(cons_demo cons_demo(owner)) */ COUNT(*) FROM cons_demo;
ALTER TABLE cons_demo MODIFY owner NOT NULL NOVALIDATE;
INSERT INTO cons_demo VALUES (null, 'x');
SELECT COUNT(*) FROM cons_demo;
@x
ALTER TABLE cons_demo MODIFY owner NULL;
--ALTER TABLE cons_demo MODIFY owner NOT NULL VALIDATE;
--ALTER TABLE cons_demo MODIFY owner NOT NULL DEFERRABLE INITIALLY DEFERRED VALIDATE;
ALTER TABLE cons_demo MODIFY owner NOT NULL DEFERRABLE VALIDATE;
SELECT COUNT(*) FROM cons_demo;
@x
DROP TABLE cons_demo2;
CREATE TABLE cons_demo2 AS SELECT * FROM scott.emp;
ALTER TABLE cons_demo2 ADD CONSTRAINT c2 CHECK (SAL > 500);
SELECT * FROM cons_demo2 WHERE sal = 100;
@x

View File

@@ -0,0 +1,43 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- analyze index density (how many rows per leaf block)
-- using SYS_OP_LBID function
-- replace the first argument of SYS_OP_LBID number with the object_id of the index you are scanning
-- also you need to modify the table name and index name hint to query the table/index of your interest
-- make sure that the index is actually accessed in the execution plan (both fast full scan and range/full
-- scans do work, but fast full scan is the fastest if you want to scan through the entire index segment)
--
-- additionally, you can use SAMPLE BLOCK syntax (below) to sample only some index blocks (when using
-- fast full scan)
COL blocks_histogram HEAD "Log(2,blocks) Histogram" FOR A30
SELECT
LPAD(NVL(TO_CHAR(rows_per_block), 'Total:'), 15, ' ') num_rows_in_blk
, blocks
, NVL2(rows_per_block, LPAD('#', LOG(2,blocks), '#'), null) blocks_histogram
FROM (
SELECT
CEIL(num_rows/10) * 10 rows_per_block
, COUNT(*) blocks
FROM (
SELECT /*+ INDEX_FFS(o IDX3_INDEXED_OBJECTS) */
count(*) num_rows
FROM
indexed_objects o -- SAMPLE BLOCK (1000) o
WHERE
owner IS NOT NULL
GROUP BY
SYS_OP_LBID( 78363, 'L', o.ROWID)
)
GROUP BY ROLLUP
( CEIL(num_rows/10) * 10 )
ORDER BY
CEIL(num_rows/10) * 10
)
/

View File

@@ -0,0 +1,20 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
select /*+ index_rs(o o(owner)) */ avg(sysdate - created) days_old
from
indexed_objects o
where
owner = 'SYS'
and object_type = 'PACKAGE'
/
@x
-- Then create an index which satisfies the additional filter column...
-- create index idx2_indexed_objects on indexed_objects (owner, object_type);
-- Then re-create the index with also the column that includes the columns selected in the query
-- drop index idx2_indexed_objects;
-- create index idx2_indexed_objects on indexed_objects (owner, object_type, created);

View File

@@ -0,0 +1,22 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
DROP TABLE t;
CREATE TABLE t AS SELECT * FROM dba_objects;
CREATE INDEX i1 ON t(MOD(object_id,4), object_id);
@gts t
SELECT /*+ INDEX_SS(t) */ * FROM t WHERE object_id = 12345;
@x
CREATE INDEX i2 ON t(MOD(SYS_CONTEXT('USERENV','SID'),4), object_id);
SELECT /*+ INDEX_SS(t) */ * FROM t WHERE object_id = 12345;
@x
ALTER TABLE t ADD x NUMBER NULL;
ALTER TABLE t MODIFY x DEFAULT MOD(SYS_CONTEXT('USERENV','SID'),16);
CREATE INDEX i3 ON t(x,object_id);
SELECT * FROM t WHERE object_id = 12345;
@x

View File

@@ -0,0 +1,26 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
select
owner, object_type, status, count(*)
from
indexed_objects o
where
owner = 'SYS'
and object_type = 'JAVA CLASS'
and created > sysdate - 3650
group by
owner,object_type,status
order by
status
/
-- Then re-create the index with also the column that we sort/group by
-- drop index idx2_indexed_objects;
-- create index idx2_indexed_objects on indexed_objects (owner, object_type, created, status);
-- And try tho swap the last 2 columns in end of the index:
-- drop index idx2_indexed_objects;
-- create index idx2_indexed_objects on indexed_objects (owner, object_type, status, created);

View File

@@ -0,0 +1,15 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
DROP TABLE selectivity_test;
CREATE TABLE selectivity_test AS
SELECT sysdate - rownum d
FROM dual connect by level <= 365;
@gts selectivity_test
@minmax d selectivity_test
@descxx selectivity_test

View File

@@ -0,0 +1,45 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
SELECT /*+ opt_param('_optimizer_use_feedback', 'false') */
d.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
, SUM(oi.quantity)
, sum(oi.unit_price * oi.quantity) total_price
FROM
oe.orders o
, oe.order_items oi
, oe.products prod
, oe.customers c
, oe.promotions prom
, hr.employees e
, hr.departments d
WHERE
-- joins
o.order_id = oi.order_id
AND oi.product_id = prod.product_id
AND o.promotion_id = prom.promo_id (+)
AND o.customer_id = c.customer_id
AND o.sales_rep_id = e.employee_id
AND d.department_id = e.department_id
-- filters
AND d.department_name = 'Sales'
AND e.first_name = 'William'
AND e.last_name = 'Smith'
AND prod.product_name = 'Mobile Web Phone'
AND c.cust_first_name = 'Gena'
AND c.cust_last_name = 'Harris'
GROUP BY
d.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
ORDER BY
total_price
/

View File

@@ -0,0 +1,53 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
SELECT /*+ leading (dep e o c oi)
use_hash(oi)
xuse_nl(oi)
xindex(oi iii)
NO_SWAP_JOIN_INPUTS(@"SEL$4B12EFE6" "C"@"SEL$1")
NO_SWAP_JOIN_INPUTS(@"SEL$5488CC2B" "C"@"MAIN")
opt_param('_optimizer_use_feedback', 'false')
qb_name(main)
*/
dep.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
, SUM(oi.quantity)
, sum(oi.unit_price * oi.quantity) total_price
FROM
hr.departments dep -- 1
, hr.employees e -- 1
, oe.orders o -- ?
, oe.order_items oi -- ?
, oe.products prod -- 1
, oe.customers c -- 1
, oe.promotions prom -- ?
WHERE
-- joins
o.order_id = oi.order_id
AND oi.product_id = prod.product_id
AND o.promotion_id = prom.promo_id (+)
AND o.customer_id = c.customer_id
AND o.sales_rep_id = e.employee_id
AND dep.department_id = e.department_id
-- filters
AND dep.department_name = 'Sales' -- 1 row
AND e.first_name = 'William' -- 1 row
AND e.last_name = 'Smith'
AND prod.product_name = 'Mobile Web Phone' -- 1 row (view)
AND c.cust_first_name = 'Gena' --
AND c.cust_last_name = 'Harris' -- 1 row
GROUP BY
dep.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
ORDER BY
total_price
/

View File

@@ -0,0 +1,50 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
SELECT /*+
opt_param('_optimizer_use_feedback', 'false')
cardinality(c o 50000)
OPT_ESTIMATE(@"SEL$1", JOIN, ("C"@"SEL$1", "E"@"SEL$1" "D"@"SEL$1" "O"@SEL$1), SCALE_ROWS=100000)
cardinality(c e d o 100000)
*/
dep.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
, SUM(oi.quantity)
, sum(oi.unit_price * oi.quantity) total_price
FROM
hr.departments dep -- 1
, hr.employees e -- 1
, oe.orders o -- ?
, oe.order_items oi -- ?
, oe.products prod -- 1
, oe.customers c -- 1
, oe.promotions prom -- ?
WHERE
-- joins
o.order_id = oi.order_id
AND oi.product_id = prod.product_id
AND o.promotion_id = prom.promo_id (+)
AND o.customer_id = c.customer_id
AND o.sales_rep_id = e.employee_id
AND dep.department_id = e.department_id
-- filters
AND dep.department_name = 'Sales' -- 1 row
AND e.first_name = 'William' -- 1 row
AND e.last_name = 'Smith'
AND prod.product_name = 'Mobile Web Phone' -- 1 row (view)
AND c.cust_first_name = 'Gena' --
AND c.cust_last_name = 'Harris' -- 1 row
GROUP BY
dep.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
ORDER BY
total_price
/

View File

@@ -0,0 +1,61 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
SELECT
/*+ opt_param('_optimizer_use_feedback', 'false')
dynamic_sampling(4) opt_param('_optimizer_use_feedback', 'false')
leading(c d e o oi)
use_hash(o)
use_hash(oi)
index(o)
index(oi)
NO_SWAP_JOIN_INPUTS(@"SEL$4B12EFE6" "I"@"SEL$2")
NO_SWAP_JOIN_INPUTS(@"SEL$4B12EFE6" "D"@"SEL$2")
*/
d.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
, SUM(oi.quantity)
, sum(oi.unit_price * oi.quantity) total_price
FROM
oe.orders o
, oe.order_items oi
, oe.products prod
, oe.customers c
, oe.promotions prom
, hr.employees e
, hr.departments d
WHERE
-- joins
o.order_id = oi.order_id
AND oi.product_id = prod.product_id
AND o.promotion_id = prom.promo_id (+)
AND o.customer_id = c.customer_id
AND o.sales_rep_id = e.employee_id
AND d.department_id = e.department_id
-- filters
AND d.department_name = 'Sales'
AND e.first_name = 'William'
AND e.last_name = 'Smith'
AND prod.product_name = 'Mobile Web Phone'
AND c.cust_first_name = 'Gena'
AND c.cust_last_name = 'Harris'
AND o.customer_id = 189 -- (select customer_id from oe.customers c2
-- WHERE c2.cust_first_name = 'Gena'
-- AND c2.cust_last_name = 'Harris')
AND oi.customer_id = 189 -- (select customer_id from oe.customers c3
-- WHERE c3.cust_first_name = 'Gena'
-- AND c3.cust_last_name = 'Harris')
GROUP BY
d.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
ORDER BY
total_price
/

View File

@@ -0,0 +1,49 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
SELECT /*+ leading (dep e o)
NO_SWAP_JOIN_INPUTS(@"SEL$5488CC2B" "C"@"MAIN")
opt_param('_optimizer_use_feedback', 'false')
qb_name(main)
*/
dep.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
, SUM(oi.quantity)
, sum(oi.unit_price * oi.quantity) total_price
FROM
hr.departments dep -- 1
, hr.employees e -- 1
, oe.orders o -- ?
, oe.order_items oi -- ?
, oe.products prod -- 1
, oe.customers c -- 1
, oe.promotions prom -- ?
WHERE
-- joins
o.order_id = oi.order_id
AND oi.product_id = prod.product_id
AND o.promotion_id = prom.promo_id (+)
AND o.customer_id = c.customer_id
AND o.sales_rep_id = e.employee_id
AND dep.department_id = e.department_id
-- filters
AND dep.department_name = 'Sales' -- 1 row
AND e.first_name = 'William' -- 1 row
AND e.last_name = 'Smith'
AND prod.product_name = 'Mobile Web Phone' -- 1 row (view)
AND c.cust_first_name = 'Gena' --
AND c.cust_last_name = 'Harris' -- 1 row
GROUP BY
dep.department_name
, e.first_name
, e.last_name
, prod.product_name
, c.cust_first_name
, c.cust_last_name
ORDER BY
total_price
/

View File

@@ -0,0 +1,73 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
INSERT INTO oe.promotions
SELECT 10+rownum promo_id, 'promotion '||to_char(10+rownum)
FROM dual CONNECT BY level < 90
/
INSERT INTO oe.promotions VALUES (100, 'online super-sale');
exec dbms_stats.gather_schema_stats('OE');
exec dbms_stats.create_stat_table('OE', 'STATS_BACKUP');
exec dbms_stats.export_schema_stats('OE', 'STATS_BACKUP', 'AST_04_TROUBLE_01');
CREATE TABLE oe.tmp AS SELECT * FROM oe.orders WHERE 1=0;
INSERT /*+ APPEND */ INTO oe.tmp
SELECT
oe.orders_seq.NEXTVAL
, sysdate -- order date
, 'online' -- order mode
, 189 -- customer id
, 12 -- order status
, 99.95 -- order_total
, 171 -- sales rep
, 100 -- promotion_id
, null -- warehouse_id -- added new column
FROM
dual CONNECT BY level <= 100000
/
COMMIT;
INSERT INTO oe.orders (
order_id NOT NULL NUMBER(12)
, order_date NOT NULL TIMESTAMP(6) WITH LOCAL TIME ZONE
, order_mode VARCHAR2(8)
, customer_id NOT NULL NUMBER(6)
, order_status NUMBER(2)
, order_total NUMBER(8,2)
, sales_rep_id NUMBER(6)
, promotion_id
, warehouse_id -- added a new column
)
SELECT * FROM oe.tmp
ORDER BY
dbms_random.random -- to increase pk clustering factor
/
COMMIT;
BEGIN
FOR i IN (SELECT order_id FROM oe.tmp) LOOP
-- such a lousy loop is needed as there's a "single row" trigger on order_items tab
INSERT INTO oe.order_items (ORDER_ID,PRODUCT_ID,UNIT_PRICE,QUANTITY)
VALUES ( i.order_id, 3337, 9.95, power(2,power(2,dbms_random.value(1,3))) );
-- commit in a loop so i wouldnt blow up my little undo tablespace
COMMIT;
END LOOP;
END;
/
-- save old "bad" stats
exec dbms_stats.export_schema_stats('OE', 'STATS_BACKUP', 'AST_04_TROUBLE_BEGIN');
-- to restore:
-- exec dbms_stats.import_schema_stats('OE', 'STATS_BACKUP', 'AST_04_TROUBLE_BEGIN', NO_INVALIDATE=>FALSE);
-- run the 04_cbo_troubleshoot_1.sql and troubleshoot! :)

25
tpt/ast/ast_setup.sql Normal file
View File

@@ -0,0 +1,25 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
DEF datafile_dir=/export/home/oracle/oradata/SOL102
-- CREATE TABLESPACE ast DATAFILE '&datafile_dir/ast.01.dbf' SIZE 200M AUTOEXTEND ON;
CREATE BIGFILE TABLESPACE ast DATAFILE SIZE 200M AUTOEXTEND ON;
CREATE USER ast IDENTIFIED BY ast DEFAULT TABLESPACE ast TEMPORARY TABLESPACE temp;
ALTER USER ast QUOTA UNLIMITED ON ast;
GRANT CREATE SESSION TO ast;
GRANT CONNECT, RESOURCE TO ast;
GRANT SELECT ANY DICTIONARY TO ast;
GRANT EXECUTE ON DBMS_LOCK TO ast;
GRANT EXECUTE ON DBMS_MONITOR TO ast;
GRANT EXECUTE ON DBMS_SQLTUNE TO ast;
GRANT EXECUTE ON DBMS_WORKLOAD_REPOSITORY TO ast;
-- for testing
GRANT DBA TO ast;

View File

@@ -0,0 +1,85 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
DROP TABLE test_objects;
DROP TABLE test_objects10;
DROP TABLE test_objects100;
DROP TABLE test_users;
DROP TABLE indexed_objects;
DROP TABLE dummy1;
DROP TABLE dummy2;
DROP TABLE indexed_source;
CREATE TABLE test_objects AS SELECT * FROM dba_objects;
CREATE TABLE test_objects10 AS SELECT * FROM test_objects WHERE rownum <= 10;
CREATE TABLE test_objects100 AS SELECT * FROM test_objects WHERE rownum <= 100;
CREATE TABLE test_users AS SELECT * FROM all_users;
CREATE TABLE indexed_objects AS SELECT * FROM dba_objects;
CREATE UNIQUE INDEX pk_obj_id ON indexed_objects (object_id);
CREATE INDEX idx_owner_name ON indexed_objects(owner,object_name);
CREATE TABLE dummy1 AS SELECT 1 a, 'one' b FROM dual;
CREATE TABLE dummy2 AS SELECT 1 a, 'one' b FROM dual;
CREATE TABLE indexed_source AS SELECT * FROM dba_source;
CREATE INDEX idx1_indexed_source ON indexed_source (owner,name,line);
EXEC DBMS_STATS.SET_PARAM('METHOD_OPT', 'FOR ALL COLUMNS SIZE REPEAT');
--EXEC DBMS_STATS.GATHER_SCHEMA_STATS('AST');
EXEC DBMS_STATS.GATHER_SCHEMA_STATS(user);
-- deterministic PL/SQL functions can utilize PL/SQL function result caching
CREATE OR REPLACE FUNCTION my_multiply(a IN NUMBER, b IN NUMBER) RETURN NUMBER AS
BEGIN
DBMS_OUTPUT.PUT_LINE('x');
RETURN a * b;
END;
/
CREATE OR REPLACE FUNCTION my_multiply_d (a IN NUMBER, b IN NUMBER) RETURN NUMBER
DETERMINISTIC
AS
BEGIN
RETURN a * b;
END;
/
CREATE OR REPLACE FUNCTION my_sqrt (a IN NUMBER) RETURN NUMBER
AS
BEGIN
RETURN SQRT(a);
END;
/
-- select max(my_sqrt(mod(rownum,100))) from dual connect by level<=100000;
CREATE OR REPLACE FUNCTION my_sqrt_d (a IN NUMBER) RETURN NUMBER
DETERMINISTIC
AS
BEGIN
RETURN SQRT(a);
END;
/
-- additional stuff in scott and other standard demo schemas
create or replace view scott.high_pay_depts as
select
*
from
scott.dept d
where
exists (select 1
from
scott.emp e
where
e.deptno = d.deptno
and e.sal > 4500
)
/

224
tpt/ast/execution_plan.txt Normal file
View File

@@ -0,0 +1,224 @@
----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2121K(100)| | | |
| 1 | SORT ORDER BY | | 3 | 6675 | 2121K (1)| 01:21:11 | | |
|* 2 | HASH JOIN | | 3 | 6675 | 2121K (1)| 01:21:11 | | |
|* 3 | HASH JOIN OUTER | | 1 | 2213 | 2121K (1)| 01:21:11 | | |
| 4 | VIEW | | 1 | 2116 | 2121K (1)| 01:21:11 | | |
| 5 | NESTED LOOPS OUTER | | 1 | 1306 | 2121K (1)| 01:21:11 | | |
| 6 | NESTED LOOPS OUTER | | 1 | 1248 | 2121K (1)| 01:21:11 | | |
| 7 | NESTED LOOPS | | 1 | 1190 | 2121K (1)| 01:21:11 | | |
|* 8 | HASH JOIN | | 1 | 1090 | 2121K (1)| 01:21:11 | | |
| 9 | VIEW | | 7 | 7329 | 2121K (1)| 01:21:11 | | |
| 10 | UNION-ALL | | | | | | | |
| 11 | NESTED LOOPS OUTER | | 1 | 648 | 31348 (2)| 00:01:12 | | |
| 12 | NESTED LOOPS | | 1 | 613 | 31347 (2)| 00:01:12 | | |
| 13 | NESTED LOOPS OUTER | | 1 | 513 | 31346 (2)| 00:01:12 | | |
| 14 | NESTED LOOPS OUTER | | 1 | 475 | 31345 (2)| 00:01:12 | | |
| 15 | NESTED LOOPS OUTER | | 1 | 412 | 31344 (2)| 00:01:12 | | |
| 16 | NESTED LOOPS | | 1 | 312 | 31343 (2)| 00:01:12 | | |
| 17 | VIEW | | 2 | 424 | 31341 (2)| 00:01:12 | | |
| 18 | UNION-ALL | | | | | | | |
| 19 | PARTITION LIST ITERATOR | | 1 | 100 | 18711 (1)| 00:00:43 | KEY | KEY |
| 20 | INLIST ITERATOR | | | | | | | |
|* 21 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_A | 1 | 100 | 18711 (1)| 00:00:43 | KEY | KEY |
|* 22 | INDEX RANGE SCAN | TABLE_A_PK | 335K| | 3751 (2)| 00:00:09 | KEY | KEY |
|* 23 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_B | 1 | 100 | 12628 (2)| 00:00:29 | 1 | 1 |
| 24 | NESTED LOOPS | | 1 | 150 | 12630 (2)| 00:00:29 | | |
| 25 | INLIST ITERATOR | | | | | | | |
|* 26 | TABLE ACCESS BY INDEX ROWID | TABLE_C | 1 | 50 | 1 (0)| 00:00:01 | | |
|* 27 | INDEX RANGE SCAN | TABLE_C_PK | 3 | | 1 (0)| 00:00:01 | | |
| 28 | PARTITION RANGE INLIST | | 36582 | | 6799 (4)| 00:00:16 | KEY(I | KEY(I |
| 29 | PARTITION LIST ITERATOR | | 36582 | | 6799 (4)| 00:00:16 | KEY | KEY |
|* 30 | INDEX RANGE SCAN | TABLE_D_PK | 36582 | | 6799 (4)| 00:00:16 | KEY(I | KEY(I |
| 31 | PARTITION RANGE INLIST | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 32 | INLIST ITERATOR | | | | | | | |
| 33 | PARTITION LIST ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|* 34 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_E | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|* 35 | INDEX RANGE SCAN | TABLE_E_PK | 1 | | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 36 | PARTITION RANGE ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
| 37 | PARTITION LIST ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
| 38 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_F | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
|* 39 | INDEX UNIQUE SCAN | TABLE_F_PK | 1 | | 0 (0)| | KEY | KEY |
| 40 | PARTITION RANGE ITERATOR | | 1 | 63 | 1 (0)| 00:00:01 | KEY | KEY |
| 41 | PARTITION LIST ITERATOR | | 1 | 63 | 1 (0)| 00:00:01 | KEY | KEY |
| 42 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_G | 1 | 63 | 1 (0)| 00:00:01 | KEY | KEY |
|* 43 | INDEX UNIQUE SCAN | TABLE_G_PK | 1 | | 0 (0)| | KEY | KEY |
| 44 | PARTITION RANGE ITERATOR | | 1 | 38 | 0 (0)| | KEY | KEY |
| 45 | PARTITION LIST ITERATOR | | 1 | 38 | 0 (0)| | KEY | KEY |
|* 46 | INDEX UNIQUE SCAN | TABLE_H_PK | 1 | 38 | 0 (0)| | KEY | KEY |
| 47 | PARTITION RANGE ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
|* 48 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_I | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
|* 49 | INDEX UNIQUE SCAN | TABLE_I_PK | 1 | | 0 (0)| | KEY | KEY |
| 50 | PARTITION RANGE ITERATOR | | 1 | 35 | 1 (0)| 00:00:01 | KEY | KEY |
| 51 | PARTITION LIST ITERATOR | | 1 | 35 | 1 (0)| 00:00:01 | KEY | KEY |
|* 52 | INDEX RANGE SCAN | TABLE_J_PK | 1 | 35 | 1 (0)| 00:00:01 | KEY | KEY |
| 53 | VIEW | | 2 | 2076 | 2089K (1)| 01:19:58 | | |
| 54 | UNION-ALL | | | | | | | |
| 55 | NESTED LOOPS OUTER | | 1 | 547 | 4574 (91)| 00:00:11 | | |
| 56 | NESTED LOOPS OUTER | | 1 | 447 | 4573 (91)| 00:00:11 | | |
| 57 | NESTED LOOPS OUTER | | 1 | 430 | 4572 (91)| 00:00:11 | | |
| 58 | NESTED LOOPS OUTER | | 1 | 413 | 4572 (91)| 00:00:11 | | |
| 59 | NESTED LOOPS | | 1 | 396 | 4571 (91)| 00:00:11 | | |
| 60 | NESTED LOOPS | | 1 | 300 | 4570 (91)| 00:00:11 | | |
|* 61 | HASH JOIN | | 1 | 200 | 4569 (91)| 00:00:11 | | |
| 62 | INLIST ITERATOR | | | | | | | |
| 63 | PARTITION RANGE ITERATOR | | 1 | 100 | 156 (4)| 00:00:01 | KEY(I | KEY(I |
| 64 | INLIST ITERATOR | | | | | | | |
| 65 | PARTITION LIST ITERATOR | | 1 | 100 | 156 (4)| 00:00:01 | KEY(I | KEY(I |
|* 66 | TABLE ACCESS BY LOCAL INDEX ROWID| TABLE_E | 1 | 100 | 156 (4)| 00:00:01 | KEY(I | KEY(I |
|* 67 | INDEX RANGE SCAN | TABLE_E_UQ | 37 | | 282 (5)| 00:00:01 | KEY(I | KEY(I |
| 68 | PARTITION LIST ALL | | 5 | 500 | 4411 (94)| 00:00:11 | 1 | 26 |
|* 69 | TABLE ACCESS FULL | TABLE_A | 5 | 500 | 4411 (94)| 00:00:11 | 1 | 26 |
| 70 | PARTITION RANGE INLIST | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|* 71 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_I | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|* 72 | INDEX UNIQUE SCAN | TABLE_I_PK | 1 | | 0 (0)| | KEY(I | KEY(I |
| 73 | TABLE ACCESS BY GLOBAL INDEX ROWID | TABLE_K | 1 | 96 | 1 (0)| 00:00:01 | ROW L | ROW L |
|* 74 | INDEX UNIQUE SCAN | TABLE_K_PK | 1 | | 0 (0)| | | |
| 75 | PARTITION RANGE ITERATOR | | 6 | 102 | 0 (0)| | KEY | KEY |
|* 76 | INDEX UNIQUE SCAN | TABLE_I_PK | 6 | 102 | 0 (0)| | KEY | KEY |
| 77 | PARTITION RANGE ITERATOR | | 6 | 102 | 4 (50)| 00:00:01 | KEY | KEY |
|* 78 | INDEX FAST FULL SCAN | TABLE_I_PK | 6 | 102 | 4 (50)| 00:00:01 | KEY | KEY |
| 79 | PARTITION RANGE ITERATOR | | 6 | 102 | 4 (50)| 00:00:01 | KEY | KEY |
|* 80 | INDEX FAST FULL SCAN | TABLE_I_PK | 6 | 102 | 4 (50)| 00:00:01 | KEY | KEY |
| 81 | PARTITION RANGE ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
| 82 | PARTITION LIST ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
| 83 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_L | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
|* 84 | INDEX UNIQUE SCAN | TABLE_L_PK | 1 | | 0 (0)| | KEY | KEY |
| 85 | NESTED LOOPS OUTER | | 1 | 570 | 2085K (1)| 01:19:48 | | |
| 86 | NESTED LOOPS OUTER | | 1 | 470 | 2085K (1)| 01:19:48 | | |
| 87 | NESTED LOOPS OUTER | | 1 | 453 | 2085K (1)| 01:19:48 | | |
| 88 | NESTED LOOPS OUTER | | 1 | 436 | 2085K (1)| 01:19:48 | | |
| 89 | NESTED LOOPS | | 1 | 419 | 2085K (1)| 01:19:48 | | |
| 90 | NESTED LOOPS | | 1 | 323 | 2085K (1)| 01:19:48 | | |
| 91 | NESTED LOOPS | | 1 | 223 | 2085K (1)| 01:19:48 | | |
| 92 | NESTED LOOPS | | 55 | 6765 | 2085K (1)| 01:19:48 | | |
| 93 | INLIST ITERATOR | | | | | | | |
|* 94 | INDEX RANGE SCAN | TABLE_C_PK | 89 | 2047 | 1 (0)| 00:00:01 | | |
| 95 | INLIST ITERATOR | | | | | | | |
| 96 | PARTITION RANGE ITERATOR | | 1 | 100 | 23427 (1)| 00:00:54 | KEY(I | KEY(I |
| 97 | PARTITION LIST INLIST | | 1 | 100 | 23427 (1)| 00:00:54 | KEY(I | KEY(I |
|* 98 | TABLE ACCESS BY LOCAL INDEX ROWID| TABLE_E | 1 | 100 | 23427 (1)| 00:00:54 | KEY(I | KEY(I |
|* 99 | INDEX RANGE SCAN | TABLE_E_PK | 60462 | | 748 (8)| 00:00:02 | KEY(I | KEY(I |
| 100 | PARTITION RANGE INLIST | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 101 | PARTITION LIST ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
|*102 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_B | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|*103 | INDEX RANGE SCAN | TABLE_D_PK | 1 | | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 104 | PARTITION RANGE INLIST | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|*105 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_I | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|*106 | INDEX UNIQUE SCAN | TABLE_I_PK | 1 | | 0 (0)| | KEY(I | KEY(I |
| 107 | TABLE ACCESS BY GLOBAL INDEX ROWID | TABLE_K | 1 | 96 | 1 (0)| 00:00:01 | ROW L | ROW L |
|*108 | INDEX UNIQUE SCAN | TABLE_K_PK | 1 | | 0 (0)| | | |
| 109 | PARTITION RANGE ITERATOR | | 6 | 102 | 0 (0)| | KEY | KEY |
|*110 | INDEX UNIQUE SCAN | TABLE_I_PK | 6 | 102 | 0 (0)| | KEY | KEY |
| 111 | PARTITION RANGE ITERATOR | | 6 | 102 | 4 (50)| 00:00:01 | KEY | KEY |
|*112 | INDEX FAST FULL SCAN | TABLE_I_PK | 6 | 102 | 4 (50)| 00:00:01 | KEY | KEY |
| 113 | PARTITION RANGE ITERATOR | | 6 | 102 | 4 (50)| 00:00:01 | KEY | KEY |
|*114 | INDEX FAST FULL SCAN | TABLE_I_PK | 6 | 102 | 4 (50)| 00:00:01 | KEY | KEY |
| 115 | PARTITION RANGE ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
| 116 | PARTITION LIST ITERATOR | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
| 117 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_L | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
|*118 | INDEX UNIQUE SCAN | TABLE_L_PK | 1 | | 0 (0)| | KEY | KEY |
| 119 | VIEW | | 2 | 2054 | 147 (2)| 00:00:01 | | |
| 120 | UNION-ALL | | | | | | | |
| 121 | NESTED LOOPS | | 1 | 362 | 74 (2)| 00:00:01 | | |
| 122 | NESTED LOOPS | | 1 | 262 | 73 (2)| 00:00:01 | | |
| 123 | NESTED LOOPS | | 1 | 200 | 72 (2)| 00:00:01 | | |
| 124 | INLIST ITERATOR | | | | | | | |
| 125 | PARTITION RANGE ITERATOR | | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
| 126 | INLIST ITERATOR | | | | | | | |
| 127 | PARTITION LIST ITERATOR | | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
|*128 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_E | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
|*129 | INDEX RANGE SCAN | TABLE_E_UQ | 6 | | 137 (2)| 00:00:01 | KEY(I | KEY(I |
| 130 | PARTITION RANGE INLIST | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 131 | PARTITION LIST ALL | | 1 | 100 | 1 (0)| 00:00:01 | 1 | 9 |
|*132 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_B | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|*133 | INDEX RANGE SCAN | TABLE_D_PK | 1 | | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 134 | TABLE ACCESS BY GLOBAL INDEX ROWID | TABLE_K | 1 | 62 | 1 (0)| 00:00:01 | ROW L | ROW L |
|*135 | INDEX UNIQUE SCAN | TABLE_K_PK | 1 | | 0 (0)| | | |
| 136 | PARTITION RANGE INLIST | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|*137 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_I | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|*138 | INDEX UNIQUE SCAN | TABLE_I_PK | 1 | | 0 (0)| | KEY(I | KEY(I |
|*139 | FILTER | | | | | | | |
|*140 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_B | 1 | 100 | 1 (0)| 00:00:01 | 1 | 1 |
| 141 | NESTED LOOPS | | 1 | 200 | 72 (2)| 00:00:01 | | |
| 142 | INLIST ITERATOR | | | | | | | |
| 143 | PARTITION RANGE ITERATOR | | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
| 144 | INLIST ITERATOR | | | | | | | |
| 145 | PARTITION LIST ITERATOR | | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
|*146 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_E | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
|*147 | INDEX RANGE SCAN | TABLE_E_UQ | 6 | | 137 (2)| 00:00:01 | KEY(I | KEY(I |
| 148 | PARTITION RANGE INLIST | | 1 | | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 149 | PARTITION LIST ALL | | 1 | | 1 (0)| 00:00:01 | 1 | 9 |
|*150 | INDEX RANGE SCAN | TABLE_D_PK | 1 | | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 151 | NESTED LOOPS OUTER | | 1 | 426 | 76 (2)| 00:00:01 | | |
| 152 | NESTED LOOPS | | 1 | 358 | 75 (2)| 00:00:01 | | |
| 153 | NESTED LOOPS OUTER | | 1 | 313 | 74 (2)| 00:00:01 | | |
| 154 | NESTED LOOPS OUTER | | 1 | 275 | 73 (2)| 00:00:01 | | |
| 155 | NESTED LOOPS | | 1 | 200 | 72 (2)| 00:00:01 | | |
| 156 | INLIST ITERATOR | | | | | | | |
| 157 | PARTITION RANGE ITERATOR | | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
| 158 | INLIST ITERATOR | | | | | | | |
| 159 | PARTITION LIST ITERATOR | | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
|*160 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_E | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
|*161 | INDEX RANGE SCAN | TABLE_E_UQ | 6 | | 137 (2)| 00:00:01 | KEY(I | KEY(I |
| 162 | PARTITION RANGE INLIST | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 163 | PARTITION LIST SINGLE | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
|*164 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_B | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|*165 | INDEX RANGE SCAN | TABLE_D_PK | 1 | | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 166 | PARTITION RANGE ITERATOR | | 1 | 75 | 1 (0)| 00:00:01 | KEY | KEY |
| 167 | PARTITION LIST ITERATOR | | 1 | 75 | 1 (0)| 00:00:01 | KEY | KEY |
| 168 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_G | 1 | 75 | 1 (0)| 00:00:01 | KEY | KEY |
|*169 | INDEX UNIQUE SCAN | TABLE_G_PK | 1 | | 0 (0)| | KEY | KEY |
| 170 | PARTITION RANGE ITERATOR | | 1 | 38 | 0 (0)| | KEY | KEY |
| 171 | PARTITION LIST ITERATOR | | 1 | 38 | 0 (0)| | KEY | KEY |
|*172 | INDEX UNIQUE SCAN | TABLE_H_PK | 1 | 38 | 0 (0)| | KEY | KEY |
| 173 | PARTITION RANGE ITERATOR | | 1 | 45 | 1 (0)| 00:00:01 | KEY | KEY |
|*174 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_I | 1 | 45 | 1 (0)| 00:00:01 | KEY | KEY |
|*175 | INDEX UNIQUE SCAN | TABLE_I_PK | 1 | | 0 (0)| | KEY | KEY |
| 176 | PARTITION RANGE ITERATOR | | 1 | 68 | 1 (0)| 00:00:01 | KEY | KEY |
| 177 | PARTITION LIST SINGLE | | 1 | 68 | 1 (0)| 00:00:01 | | |
| 178 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_F | 1 | 68 | 1 (0)| 00:00:01 | KEY | KEY |
|*179 | INDEX UNIQUE SCAN | TABLE_F_PK | 1 | | 0 (0)| | KEY | KEY |
| 180 | NESTED LOOPS OUTER | | 1 | 423 | 76 (2)| 00:00:01 | | |
| 181 | NESTED LOOPS | | 1 | 355 | 75 (2)| 00:00:01 | | |
| 182 | NESTED LOOPS OUTER | | 1 | 310 | 74 (2)| 00:00:01 | | |
| 183 | NESTED LOOPS OUTER | | 1 | 272 | 73 (2)| 00:00:01 | | |
| 184 | NESTED LOOPS | | 1 | 200 | 72 (2)| 00:00:01 | | |
| 185 | INLIST ITERATOR | | | | | | | |
| 186 | PARTITION RANGE ITERATOR | | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
| 187 | INLIST ITERATOR | | | | | | | |
| 188 | PARTITION LIST ITERATOR | | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
|*189 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_E | 1 | 100 | 71 (2)| 00:00:01 | KEY(I | KEY(I |
|*190 | INDEX RANGE SCAN | TABLE_E_UQ | 6 | | 137 (2)| 00:00:01 | KEY(I | KEY(I |
| 191 | PARTITION RANGE INLIST | | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 192 | PARTITION LIST SINGLE | | 1 | 100 | 1 (0)| 00:00:01 | KEY | KEY |
|*193 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_B | 1 | 100 | 1 (0)| 00:00:01 | KEY(I | KEY(I |
|*194 | INDEX RANGE SCAN | TABLE_D_PK | 1 | | 1 (0)| 00:00:01 | KEY(I | KEY(I |
| 195 | PARTITION RANGE ITERATOR | | 1 | 72 | 1 (0)| 00:00:01 | KEY | KEY |
| 196 | PARTITION LIST ITERATOR | | 1 | 72 | 1 (0)| 00:00:01 | KEY | KEY |
| 197 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_G | 1 | 72 | 1 (0)| 00:00:01 | KEY | KEY |
|*198 | INDEX UNIQUE SCAN | TABLE_G_PK | 1 | | 0 (0)| | KEY | KEY |
| 199 | PARTITION RANGE ITERATOR | | 1 | 38 | 0 (0)| | KEY | KEY |
| 200 | PARTITION LIST ITERATOR | | 1 | 38 | 0 (0)| | KEY | KEY |
|*201 | INDEX UNIQUE SCAN | TABLE_H_PK | 1 | 38 | 0 (0)| | KEY | KEY |
| 202 | PARTITION RANGE ITERATOR | | 1 | 45 | 1 (0)| 00:00:01 | KEY | KEY |
|*203 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_I | 1 | 45 | 1 (0)| 00:00:01 | KEY | KEY |
|*204 | INDEX UNIQUE SCAN | TABLE_I_PK | 1 | | 0 (0)| | KEY | KEY |
| 205 | PARTITION RANGE ITERATOR | | 1 | 68 | 1 (0)| 00:00:01 | KEY | KEY |
| 206 | PARTITION LIST SINGLE | | 1 | 68 | 1 (0)| 00:00:01 | | |
| 207 | TABLE ACCESS BY LOCAL INDEX ROWID | TABLE_F | 1 | 68 | 1 (0)| 00:00:01 | KEY | KEY |
|*208 | INDEX UNIQUE SCAN | TABLE_F_PK | 1 | | 0 (0)| | KEY | KEY |
| 209 | TABLE ACCESS FULL | TABLE_M | 252 | 10836 | 2 (0)| 00:00:01 | | |
| 210 | TABLE ACCESS BY INDEX ROWID | TABLE_N | 1 | 100 | 1 (0)| 00:00:01 | | |
|*211 | INDEX UNIQUE SCAN | TABLE_N_PK | 1 | | 0 (0)| | | |
| 212 | TABLE ACCESS BY INDEX ROWID | TABLE_O | 1 | 58 | 1 (0)| 00:00:01 | | |
|*213 | INDEX RANGE SCAN | TABLE_O_PK | 1 | | 0 (0)| | | |
| 214 | TABLE ACCESS BY INDEX ROWID | TABLE_P | 1 | 58 | 1 (0)| 00:00:01 | | |
|*215 | INDEX RANGE SCAN | TABLE_P_IDX | 1 | | 0 (0)| | | |
| 216 | TABLE ACCESS FULL | TABLE_Q | 227 | 22019 | 2 (0)| 00:00:01 | | |
| 217 | VIEW | | 252 | 3024 | 3 (34)| 00:00:01 | | |
| 218 | SORT UNIQUE | | 252 | 3024 | 3 (34)| 00:00:01 | | |
| 219 | TABLE ACCESS FULL | TABLE_M | 252 | 3024 | 2 (0)| 00:00:01 | | |
----------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -0,0 +1,100 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
SET LINES 1000 PAGES 5000 TRIMSPOOL ON TRIMOUT ON TAB OFF
COL owner FOR A15
COL object_name FOR A30
WITH trends AS (
SELECT
o.owner
, o.object_name
, o.subobject_name
, o.object_type
, MIN(ih.savtime) first_sample
, MAX(ih.savtime) last_sample
, REGR_SLOPE(ih.rowcnt / NULLIF(ih.leafcnt,0), (SYSDATE-CAST(ih.savtime AS DATE)) ) regr1
, REGR_SLOPE(ih.rowcnt, ih.leafcnt) regr2
, ROUND(MIN(ih.rowcnt / NULLIF(ih.leafcnt,0))) min_avg_rows_per_block
, ROUND(MAX(ih.rowcnt / NULLIF(ih.leafcnt,0))) max_avg_rows_per_block
, MIN(ih.rowcnt) min_rowcnt
, MAX(ih.rowcnt) max_rowcnt
, MIN(ih.leafcnt) min_leafcnt
, MAX(ih.leafcnt) max_leafcnt
, MIN(ih.lblkkey) min_lblkkey
, MAX(ih.lblkkey) max_lblkkey
, MIN(ih.dblkkey) min_dblkkey
, MAX(ih.dblkkey) max_dblkkey
, MIN(ih.blevel)+1 min_height
, MAX(ih.blevel)+1 max_height
FROM
dba_objects o
, sys.wri$_optstat_ind_history ih
WHERE
o.object_id = ih.obj#
AND o.object_type LIKE 'INDEX%'
AND (
UPPER(o.object_name) LIKE
UPPER(CASE
WHEN INSTR('&1','.') > 0 THEN
SUBSTR('&1',INSTR('&1','.')+1)
ELSE
'&1'
END
)
AND UPPER(o.owner) LIKE
CASE WHEN INSTR('&1','.') > 0 THEN
UPPER(SUBSTR('&1',1,INSTR('&1','.')-1))
ELSE
user
END
)
GROUP BY
o.owner
, o.object_name
, o.subobject_name
, o.object_type
ORDER BY
-- ih.savtime
regr1 DESC NULLS LAST
)
SELECT * FROM (
SELECT
t.owner
, t.object_name
, t.subobject_name partition_name
, t.object_type
, ROUND(s.bytes / 1048576) current_mb
, CAST(first_sample AS DATE) first_sample
, CAST(last_sample AS DATE) last_sample
, min_avg_rows_per_block
, max_avg_rows_per_block
, min_leafcnt
, max_leafcnt
, min_lblkkey
, max_lblkkey
, min_dblkkey
, max_dblkkey
, t.regr1
, t.regr2
--, ROUND(SUM(s.bytes) / 1048576) mb_sum
--, COUNT(*)
FROM
trends t
, dba_segments s
WHERE
t.owner = s.owner
AND t.object_name = s.segment_name
AND t.object_type = s.segment_type
AND (t.subobject_name = s.partition_name OR (t.subobject_name IS NULL AND s.partition_name IS NULL))
--GROUP BY
-- t.owner
-- , t.object_name
-- , t.object_type
-- , t.subobject_name
ORDER BY regr1 DESC NULLS LAST
)
WHERE
ROWNUM<=20
/

View File

@@ -0,0 +1,26 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
COL owner FOR A15
COL object_name FOR A30
SELECT
o.owner
, o.object_name
, o.object_type
, ROUND(ih.rowcnt / NULLIF(ih.leafcnt,0)) avg_rows_per_block
, ih.rowcnt
, ih.leafcnt
, ih.lblkkey
, ih.dblkkey
, ih.blevel
FROM
dba_objects o
, sys.wri$_optstat_ind_history ih
WHERE
o.object_id = ih.obj#
AND o.object_type LIKE 'INDEX%'
AND o.object_name LIKE '&1'
ORDER BY
ih.savtime
/

View File

@@ -0,0 +1,9 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
SELECT
i.index_name
FROM

View File

@@ -0,0 +1,20 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- enable physical IO tracing
@seg soe.orders
@ind soe.orders
@descxx soe.orders
ALTER SESSION SET EVENTS '10298 trace name context forever, level 1';
EXEC SYS.DBMS_MONITOR.SESSION_TRACE_ENABLE(waits=>TRUE);
SET TIMING ON
SET AUTOTRACE ON STAT
PAUSE Press enter to start...
SELECT /*+ MONITOR INDEX(o, o(warehouse_id)) */ SUM(order_total) FROM soe.orders o WHERE warehouse_id BETWEEN 400 AND 599;
SET AUTOTRACE OFF

View File

@@ -0,0 +1,52 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- DROP TABLE s;
-- DROP TABLE t;
--
-- CREATE TABLE s AS SELECT * FROM dba_segments;
-- CREATE TABLE t AS SELECT * FROM dba_tables;
--
-- SET TIMING ON
-- SELECT COUNT(*)
-- FROM
-- t
-- , s
-- WHERE
-- (t.owner = s.owner AND t.table_name = s.segment_name)
-- OR (t.owner = s.owner AND UPPER(t.table_name) = UPPER(s.segment_name))
-- /
--
-- @x
SELECT
/*+
ALL_ROWS
MERGE(@"SEL$2")
FULL(@"SEL$64EAE176" "T"@"SEL$2")
NO_ACCESS(@"SEL$64EAE176" "from$_subquery$_004"@"SEL$2")
LEADING(@"SEL$64EAE176" "T"@"SEL$2" "from$_subquery$_004"@"SEL$2")
USE_HASH(@"SEL$64EAE176" "from$_subquery$_004"@"SEL$2")
FULL(@"SEL$1" "S"@"SEL$1")
*/
COUNT(*)
FROM
t
LEFT OUTER JOIN
s
ON (
(t.owner = s.owner AND t.table_name = s.segment_name)
OR (t.owner = s.owner AND UPPER(t.table_name) = UPPER(s.segment_name))
);
-- @x
-- SELECT COUNT(*) FROM (
-- SELECT * FROM t LEFT JOIN s ON (t.owner = s.owner AND t.table_name = s.segment_name)
-- UNION
-- SELECT * FROM t LEFT JOIN s ON (t.owner = s.owner AND UPPER(t.table_name) = UPPER(s.segment_name))
-- );
--
-- @x

View File

@@ -0,0 +1,72 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- A-Times were misestimated with the default sampling
-- ALTER SESSION SET "_rowsource_statistics_sampfreq"=1;
ALTER SESSION SET "_serial_direct_read"=ALWAYS;
SELECT /*+ MONITOR test2a */
SUM(LENGTH(object_name)) + SUM(LENGTH(object_type)) + SUM(LENGTH(owner))
FROM
test_objects_100m o
WHERE
o.owner = (SELECT u.username FROM test_users u WHERE user_id = 13)
/
@getprev
@xpi &prev_sql_id
@xia &prev_sql_id &prev_child_number
-- @ash/asqlmon &prev_sql_id &prev_child_number
-- @sqlidx &prev_sql_id &prev_child_number
SELECT /*+ MONITOR NO_PUSH_SUBQ(@"SEL$2") test2b */
SUM(LENGTH(object_name)) + SUM(LENGTH(object_type)) + SUM(LENGTH(owner))
FROM
test_objects_100m o
WHERE
o.owner = (SELECT u.username FROM test_users u WHERE user_id = 13)
/
@getprev
-- @ash/asqlmon &prev_sql_id &prev_child_number
-- @sqlidx &prev_sql_id &prev_child_number
@xpi &prev_sql_id
@xia &prev_sql_id &prev_child_number
-- ALTER SESSION SET "_rowsource_statistics_sampfreq"=128;
SELECT /*+ MONITOR OPT_PARAM('cell_offload_processing', 'false') test3a */
SUM(LENGTH(object_name)) + SUM(LENGTH(object_type)) + SUM(LENGTH(owner))
FROM
test_objects_100m o
WHERE
o.owner = (SELECT u.username FROM test_users u WHERE user_id = 13)
/
SELECT /*+ MONITOR NO_PUSH_SUBQ(@"SEL$2") OPT_PARAM('cell_offload_processing', 'false') test3b */
SUM(LENGTH(object_name)) + SUM(LENGTH(object_type)) + SUM(LENGTH(owner))
FROM
test_objects_100m o
WHERE
o.owner = (SELECT u.username FROM test_users u WHERE user_id = 13)
/
SELECT /*+ MONITOR PUSH_SUBQ(@"SEL$2") OPT_PARAM('cell_offload_processing', 'true') test4a */
SUM(LENGTH(object_name)) + SUM(LENGTH(object_type)) + SUM(LENGTH(owner))
FROM
test_objects_100m o
WHERE
o.owner = (SELECT u.username FROM test_users u WHERE user_id = 13)
/
SELECT /*+ MONITOR NO_PUSH_SUBQ(@"SEL$2") OPT_PARAM('cell_offload_processing', 'true') test4b */
SUM(LENGTH(object_name)) + SUM(LENGTH(object_type)) + SUM(LENGTH(owner))
FROM
test_objects_100m o
WHERE
o.owner = (SELECT u.username FROM test_users u WHERE user_id = 13)
/

View File

@@ -0,0 +1,39 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- DROP TABLE test_users;
-- DROP TABLE test_objects;
CREATE TABLE test_users AS SELECT * FROM all_users;
CREATE TABLE test_objects AS SELECT * FROM all_objects;
@gts test_users
@gts test_objects
@53on
SELECT /*+ GATHER_PLAN_STATISTICS */
u.username
, (SELECT MAX(created) FROM test_objects o WHERE o.owner = u.username)
FROM
test_users u
WHERE
username LIKE 'S%'
/
@53off
@xall
@53on
-- ALTER SESSION SET "_optimizer_unnest_scalar_sq" = FALSE;
SELECT /*+ GATHER_PLAN_STATISTICS NO_UNNEST(@ssq) */
u.username
, (SELECT /*+ QB_NAME(ssq) */ MAX(created) FROM test_objects o WHERE o.owner = u.username)
FROM
test_users u
WHERE
username LIKE 'S%'
/
@53off
@xall

55
tpt/ast/soe_query.sql Normal file
View File

@@ -0,0 +1,55 @@
------------------------------------------------------------------------------
--
-- Copyright 2017 Tanel Poder ( tanel@tanelpoder.com | http://tanelpoder.com )
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
------------------------------------------------------------------------------
ALTER SESSION SET plsql_optimize_level = 0;
DECLARE
n NUMBER;
BEGIN
FOR i IN 1 .. &1 LOOP
n := DBMS_RANDOM.VALUE;
EXECUTE IMMEDIATE q'[SELECT
prod.product_name
, c.cust_first_name
, c.cust_last_name
, SUM(oi.quantity)
, sum(oi.unit_price * oi.quantity) total_price
FROM
soe.orders o
, soe.order_items oi
, soe.products prod
, soe.customers c
WHERE
-- joins
o.order_id = oi.order_id
AND oi.product_id = prod.product_id
AND o.customer_id = c.customer_id
-- filters
AND prod.product_name = 'Mobile Web Phone'||:v
AND LOWER(c.cust_first_name) = LOWER('Gena'||:v)
AND LOWER(c.cust_last_name) = LOWER('Harris'||:v)
GROUP BY
prod.product_name
, c.cust_first_name
, c.cust_last_name
ORDER BY
total_price]'
USING n, n, n;
END LOOP;
END LOOP;
/

View File

@@ -0,0 +1,25 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
-- starting from 10g, the push_subq hint must be specified in the subquery block
-- you wish to push earlier (or with the @subq hint addressing)
select
e.*
, d.dname
from
scott.emp e
, scott.dept d
where
e.deptno = d.deptno
and exists (
select /*+ no_unnest push_subq */
1
from
scott.bonus b
where
b.ename = e.ename
and b.job = e.job
)
/

View File

@@ -0,0 +1,32 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
DROP TABLE tcoal;
DROP SEQUENCE scoal;
CREATE TABLE tcoal (id NUMBER, a VARCHAR2(100), b VARCHAR2(100)) TABLESPACE users;
CREATE INDEX icoal1 ON tcoal(id) TABLESPACE users;
CREATE INDEX icoal2 ON tcoal(id,a) TABLESPACE users;
CREATE INDEX icoal3 ON tcoal(b) TABLESPACE users;
CREATE SEQUENCE scoal CACHE 10000;
BEGIN FOR i IN 1..100 LOOP
INSERT INTO tcoal SELECT scoal.NEXTVAL, DBMS_RANDOM.STRING('a', 20), DBMS_RANDOM.STRING('a', 20)
FROM dual CONNECT BY LEVEL <= 10000;
COMMIT;
DBMS_STATS.GATHER_INDEX_STATS(user, 'ICOAL1');
DBMS_STATS.GATHER_INDEX_STATS(user, 'ICOAL2');
DBMS_STATS.GATHER_INDEX_STATS(user, 'ICOAL3');
END LOOP; END;
/
BEGIN FOR i in 1..100 LOOP
DELETE FROM tcoal WHERE MOD(id,100)!=0 AND rownum <= 10000;
INSERT INTO tcoal SELECT scoal.NEXTVAL, DBMS_RANDOM.STRING('a', 20), DBMS_RANDOM.STRING('a', 20)
FROM dual CONNECT BY LEVEL <= 10000;
DBMS_STATS.GATHER_INDEX_STATS(user, 'ICOAL1');
DBMS_STATS.GATHER_INDEX_STATS(user, 'ICOAL2');
DBMS_STATS.GATHER_INDEX_STATS(user, 'ICOAL3');
END LOOP; END;
/

116
tpt/ast/test_plan.txt Normal file
View File

@@ -0,0 +1,116 @@
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 2 |00:00:06.65 | 50499 | 2086 | 1041 | | | |
| 1 | TEMP TABLE TRANSFORMATION | | 1 | | 2 |00:00:06.65 | 50499 | 2086 | 1041 | | | |
| 2 | LOAD AS SELECT | | 1 | | 0 |00:00:06.32 | 48405 | 2 | 1041 | 530K| 530K| 530K (0)|
|* 3 | TABLE ACCESS BY INDEX ROWID | SUM$ | 3 | 1 | 0 |00:00:00.01 | 3 | 0 | 0 | | | |
|* 4 | INDEX UNIQUE SCAN | I_SUM$_1 | 3 | 1 | 3 |00:00:00.01 | 2 | 0 | 0 | | | |
| 5 | TABLE ACCESS BY INDEX ROWID | OBJ$ | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 6 | INDEX RANGE SCAN | I_OBJ1 | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 7 | FILTER | | 1 | | 73027 |00:00:05.77 | 47342 | 2 | 0 | | | |
|* 8 | HASH JOIN | | 1 | 74860 | 74936 |00:00:00.79 | 948 | 0 | 0 | 1063K| 1063K| 1234K (0)|
| 9 | TABLE ACCESS FULL | USER$ | 1 | 104 | 104 |00:00:00.01 | 7 | 0 | 0 | | | |
|* 10 | HASH JOIN | | 1 | 74860 | 74936 |00:00:00.51 | 941 | 0 | 0 | 981K| 981K| 1254K (0)|
| 11 | INDEX FULL SCAN | I_USER2 | 1 | 104 | 104 |00:00:00.01 | 1 | 0 | 0 | | | |
|* 12 | TABLE ACCESS FULL | OBJ$ | 1 | 74860 | 74936 |00:00:00.18 | 940 | 0 | 0 | | | |
|* 13 | TABLE ACCESS BY INDEX ROWID | IND$ | 4995 | 1 | 4087 |00:00:00.04 | 933 | 0 | 0 | | | |
|* 14 | INDEX UNIQUE SCAN | I_IND1 | 4995 | 1 | 4995 |00:00:00.01 | 134 | 0 | 0 | | | |
|* 15 | HASH JOIN | | 25955 | 1 | 24502 |00:00:03.60 | 26661 | 0 | 0 | 981K| 981K| 1051K (0)|
|* 16 | INDEX RANGE SCAN | I_OBJAUTH1 | 25955 | 1 | 24747 |00:00:00.19 | 26661 | 0 | 0 | | | |
| 17 | FIXED TABLE FULL | X$KZSRO | 24589 | 100 | 27424 |00:00:00.18 | 0 | 0 | 0 | | | |
|* 18 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 19 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
| 20 | NESTED LOOPS | | 1645 | 1 | 96 |00:00:00.01 | 1865 | 0 | 0 | | | |
|* 21 | INDEX RANGE SCAN | I_OBJAUTH1 | 1645 | 1 | 133 |00:00:00.01 | 1865 | 0 | 0 | | | |
|* 22 | FIXED TABLE FULL | X$KZSRO | 133 | 1 | 96 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 23 | HASH JOIN | | 2845 | 1 | 1478 |00:00:00.48 | 3051 | 0 | 0 | 990K| 990K| 485K (0)|
|* 24 | INDEX RANGE SCAN | I_OBJAUTH1 | 2845 | 1 | 1551 |00:00:00.02 | 3051 | 0 | 0 | | | |
| 25 | FIXED TABLE FULL | X$KZSRO | 1493 | 100 | 1853 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 26 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
| 27 | NESTED LOOPS | | 1255 | | 0 |00:00:00.35 | 7429 | 0 | 0 | | | |
| 28 | NESTED LOOPS | | 1255 | 1 | 0 |00:00:00.35 | 7429 | 0 | 0 | | | |
| 29 | NESTED LOOPS | | 1255 | 1 | 0 |00:00:00.35 | 7429 | 0 | 0 | | | |
| 30 | NESTED LOOPS | | 1255 | 1 | 28865 |00:00:00.25 | 4702 | 0 | 0 | | | |
| 31 | MERGE JOIN CARTESIAN | | 1255 | 1 | 28865 |00:00:00.12 | 3445 | 0 | 0 | | | |
|* 32 | INDEX RANGE SCAN | I_OBJ5 | 1255 | 1 | 1255 |00:00:00.01 | 3445 | 0 | 0 | | | |
| 33 | BUFFER SORT | | 1255 | 100 | 28865 |00:00:00.07 | 0 | 0 | 0 | 2048 | 2048 | 2048 (0)|
| 34 | FIXED TABLE FULL | X$KZSRO | 1255 | 100 | 28865 |00:00:00.03 | 0 | 0 | 0 | | | |
|* 35 | INDEX RANGE SCAN | I_USER2 | 28865 | 1 | 28865 |00:00:00.07 | 1257 | 0 | 0 | | | |
|* 36 | INDEX RANGE SCAN | I_OBJAUTH1 | 28865 | 1 | 0 |00:00:00.06 | 2727 | 0 | 0 | | | |
|* 37 | INDEX RANGE SCAN | I_DEPENDENCY1 | 0 | 3 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 38 | TABLE ACCESS BY INDEX ROWID | DEPENDENCY$ | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 39 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
| 40 | NESTED LOOPS | | 617 | 1 | 7 |00:00:00.01 | 1923 | 0 | 0 | | | |
| 41 | NESTED LOOPS | | 617 | 1 | 19 |00:00:00.01 | 1923 | 0 | 0 | | | |
|* 42 | TABLE ACCESS BY INDEX ROWID | TRIGGER$ | 617 | 1 | 592 |00:00:00.01 | 1245 | 0 | 0 | | | |
|* 43 | INDEX UNIQUE SCAN | I_TRIGGER2 | 617 | 1 | 617 |00:00:00.01 | 628 | 0 | 0 | | | |
|* 44 | INDEX RANGE SCAN | I_OBJAUTH1 | 592 | 1 | 19 |00:00:00.01 | 678 | 0 | 0 | | | |
|* 45 | FIXED TABLE FULL | X$KZSRO | 19 | 1 | 7 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 46 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
| 47 | NESTED LOOPS | | 240 | | 0 |00:00:00.07 | 1471 | 0 | 0 | | | |
| 48 | NESTED LOOPS | | 240 | 1 | 0 |00:00:00.07 | 1471 | 0 | 0 | | | |
| 49 | NESTED LOOPS | | 240 | 1 | 0 |00:00:00.07 | 1471 | 0 | 0 | | | |
| 50 | NESTED LOOPS | | 240 | 1 | 5727 |00:00:00.05 | 926 | 0 | 0 | | | |
| 51 | MERGE JOIN CARTESIAN | | 240 | 1 | 5727 |00:00:00.02 | 684 | 0 | 0 | | | |
|* 52 | INDEX RANGE SCAN | I_OBJ5 | 240 | 1 | 249 |00:00:00.01 | 684 | 0 | 0 | | | |
| 53 | BUFFER SORT | | 249 | 100 | 5727 |00:00:00.01 | 0 | 0 | 0 | 2048 | 2048 | 2048 (0)|
| 54 | FIXED TABLE FULL | X$KZSRO | 240 | 100 | 5520 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 55 | INDEX RANGE SCAN | I_USER2 | 5727 | 1 | 5727 |00:00:00.01 | 242 | 0 | 0 | | | |
|* 56 | INDEX RANGE SCAN | I_OBJAUTH1 | 5727 | 1 | 0 |00:00:00.01 | 545 | 0 | 0 | | | |
|* 57 | INDEX RANGE SCAN | I_DEPENDENCY1 | 0 | 3 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 58 | TABLE ACCESS BY INDEX ROWID | DEPENDENCY$ | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 59 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 60 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 61 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 62 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 63 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 64 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 65 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 66 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 67 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
| 68 | VIEW | | 52 | 1 | 52 |00:00:00.01 | 0 | 0 | 0 | | | |
| 69 | FAST DUAL | | 52 | 1 | 52 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 70 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 71 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 72 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 73 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 74 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 75 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 76 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 77 | FIXED TABLE FULL | X$KZSPR | 1 | 1 | 1 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 78 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 79 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 80 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 81 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 82 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 83 | INDEX RANGE SCAN | I_OBJAUTH1 | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 84 | FIXED TABLE FULL | X$KZSRO | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 85 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 86 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 87 | INDEX RANGE SCAN | I_OBJAUTH1 | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 88 | FIXED TABLE FULL | X$KZSRO | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 89 | FIXED TABLE FULL | X$KZSPR | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 90 | VIEW | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 91 | SORT GROUP BY | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | 73728 | 73728 | |
| 92 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 93 | MERGE JOIN CARTESIAN | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 94 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 95 | INDEX UNIQUE SCAN | I_OLAP_CUBES$ | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 96 | TABLE ACCESS BY INDEX ROWID| OLAP_DIMENSIONALITY$ | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|* 97 | INDEX RANGE SCAN | I_OLAP_DIMENSIONALITY$ | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 98 | BUFFER SORT | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | 73728 | 73728 | |
| 99 | INDEX FULL SCAN | I_OLAP_CUBE_DIMENSIONS$ | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|*100 | INDEX RANGE SCAN | I_OBJ1 | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 101 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|*102 | INDEX FULL SCAN | I_USER2 | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
|*103 | INDEX RANGE SCAN | I_OBJ4 | 0 | 1 | 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 104 | UNION-ALL | | 1 | | 2 |00:00:00.33 | 2091 | 2084 | 0 | | | |
| 105 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.18 | 1047 | 1042 | 0 | | | |
| 106 | VIEW | | 1 | 31935 | 73027 |00:00:00.13 | 1047 | 1042 | 0 | | | |
| 107 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6637_489CA79 | 1 | 31935 | 73027 |00:00:00.07 | 1047 | 1042 | 0 | | | |
| 108 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.15 | 1044 | 1042 | 0 | | | |
| 109 | VIEW | | 1 | 31935 | 73027 |00:00:00.12 | 1044 | 1042 | 0 | | | |
| 110 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6637_489CA79 | 1 | 31935 | 73027 |00:00:00.05 | 1044 | 1042 | 0 | | | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

10920
tpt/ast/trace/a.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
#!/bin/sh
cat $1 | awk '
function p(str) { printf("%6d: %s\n", NR, str) ; return 0 }
/Now joining|Join order/{ p($0) }
/^Best::/{ x=1 ; p($0) }
(!/Best::/ && x ==1) { p($0) ; x=0 }
'

16
tpt/ast/use_concat.sql Normal file
View File

@@ -0,0 +1,16 @@
-- Copyright 2018 Tanel Poder. All rights reserved. More info at http://tanelpoder.com
-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for terms & conditions.
DROP TABLE t;
CREATE TABLE t AS SELECT * FROM dba_objects;
CREATE INDEX t_i1 ON t (object_id);
CREATE INDEX t_i2 ON t (data_object_id);
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'T');
SELECT owner FROM t WHERE object_id = 123 OR data_object_id = 456;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null,'+OUTLINE'));