Performance Tuning Oracle SQL involving huge tables - sql

I have an Oracle SQL query that involves joins with 4 large tables along with few small tables.
Large tables are TBL_1, TBL_2, TBL_3, TBL4 each having approx 8M records. Rest are small tables having less than 10K records.
The problem: Query takes more than 3 minutes even if there is no data to return.
The table and index stats are up-to-date. There are no stale stats on these tables.
I've tried using hints but it didn't work.
Please see my observations below:
Query:
SELECT a.*, ROWNUM AS rnm
FROM ( SELECT c.idntfr,
pr.program_name AS "Program",
e.case_number,
(SELECT DECODE (s.status_name,
'EA', 'A',
'ED', 'D',
'EU', 'U',
s.status_name)
FROM TBL_5 ms, status s
WHERE ms.status_type_cid = 7
AND mbr_sid = c.mbr_sid
AND ms.status_type_cid = s.status_type_cid
AND s.status_cid = ms.status_cid
AND ms.oprtnl_flag = 'A'
AND SYSDATE BETWEEN ms.from_date AND ms.TO_DATE),
DECODE (
LENGTH (TRIM (e.social_security_nmbr)),
NULL, 'Not Available',
( SUBSTR (e.social_security_nmbr, 1, 3)
|| '-'
|| SUBSTR (e.social_security_nmbr, 4, 2)
|| '-'
|| SUBSTR (e.social_security_nmbr, 6, 4)))
AS "SSN",
e.last_name || ',' || e.first_name || ' ' || e.middle_name,
TO_CHAR (e.injury_date, 'MM/dd/yyyy'),
DECODE (e.gender_lkpcd,
'M', 'Male',
'F', 'Female',
'U', 'Unknown'),
e.mbr_sid,
pr.program_cid,
e.last_name,
e.social_security_nmbr,
e.first_name AS
FROM TBL_1 c,
program pr,
TBL_2 e,
TBL_3 mai,
TBL_4 uaxou
WHERE c.mbr_sid = e.mbr_sid
AND c.mbr_sid = mai.mbr_sid
AND c.oprtnl_flag = 'A'
AND c.idntfr_type_cid = 423
AND TRUNC (SYSDATE) BETWEEN c.from_date AND c.TO_DATE
AND TRUNC (SYSDATE) BETWEEN e.from_date AND e.TO_DATE
AND e.oprtnl_flag = 'A'
AND e.status_cid = 2
AND mai.oprtnl_flag = 'A'
AND mai.status_cid = 2
AND TRUNC (SYSDATE) BETWEEN mai.from_date AND mai.TO_DATE
AND e.program_code = pr.program_code
AND pr.oprtnl_flag = 'A'
AND uaxou.user_acct_sid = 1
AND uaxou.oprtnl_flag = 'A'
AND SYSDATE BETWEEN uaxou.from_date AND uaxou.TO_DATE
AND uaxou.org_unit_sid = mai.org_unit_sid
ORDER BY "Program" ASC) a
WHERE ROWNUM < 102;
There is no data for the following condition
AND uaxou.user_acct_sid = 1
Expected Result: Response time should be under 4 seconds if NO data is returned.
Explain Plan:
Plan hash value: 2272581586
---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 22220 | 1361 (1)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 58 | 7 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 58 | 7 (0)| 00:00:01 |
|* 3 | TABLE ACCESS BY INDEX ROWID BATCHED| TBL_5 | 1 | 31 | 6 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | XIF1TBL_5 | 8 | | 3 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | XPKSTATUS | 1 | | 0 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID | STATUS | 1 | 27 | 1 (0)| 00:00:01 |
|* 7 | COUNT STOPKEY | | | | | |
| 8 | VIEW | | 169 | 37180 | 1361 (1)| 00:00:01 |
| 9 | NESTED LOOPS | | 169 | 36166 | 767 (0)| 00:00:01 |
| 10 | NESTED LOOPS | | 11904 | 36166 | 767 (0)| 00:00:01 |
| 11 | NESTED LOOPS | | 62 | 11284 | 333 (0)| 00:00:01 |
| 12 | NESTED LOOPS | | 45 | 6660 | 108 (0)| 00:00:01 |
| 13 | NESTED LOOPS | | 33 | 3564 | 9 (0)| 00:00:01 |
|* 14 | TABLE ACCESS BY INDEX ROWID | PROGRAM | 5 | 70 | 2 (0)| 00:00:01 |
| 15 | INDEX FULL SCAN | XAK1OWCP_PROGRAM | 2 | | 1 (0)| 00:00:01 |
|* 16 | TABLE ACCESS FULL | TBL_2 | 20 | 1880 | 4 (0)| 00:00:01 |
|* 17 | TABLE ACCESS BY INDEX ROWID | TBL_1 | 1 | 40 | 3 (0)| 00:00:01 |
|* 18 | INDEX RANGE SCAN | TUNE_WS_19NOV10_X2 | 1 | | 2 (0)| 00:00:01 |
|* 19 | TABLE ACCESS BY INDEX ROWID | TBL_3 | 1 | 34 | 5 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | XIE2_TBL_3 | 3 | | 2 (0)| 00:00:01 |
|* 21 | INDEX RANGE SCAN | XIF3TBL_4 | 192 | | 1 (0)| 00:00:01 |
|* 22 | TABLE ACCESS BY INDEX ROWID | TBL_4 | 3 | 96 | 7 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("MS"."STATUS_TYPE_CID"=7 AND "MS"."OPRTNL_FLAG"='A' AND "MS"."TO_DATE">=SYSDATE#! AND
"MS"."FROM_DATE"<=SYSDATE#!)
4 - access("MBR_SID"=:B1)
5 - access("S"."STATUS_TYPE_CID"=7 AND "S"."STATUS_CID"="MS"."STATUS_CID")
7 - filter(ROWNUM<102)
14 - filter("PR"."OPRTNL_FLAG"='A')
16 - filter("E"."PROGRAM_CODE"="PR"."PROGRAM_CODE" AND "E"."OPRTNL_FLAG"='A' AND "E"."STATUS_CID"=2 AND
"E"."FROM_DATE"<=TRUNC(SYSDATE#!) AND TRUNC(INTERNAL_FUNCTION("FROM_DATE"))<=TRUNC(TRUNC(SYSDATE#!)) AND
"E"."TO_DATE">=TRUNC(SYSDATE#!) AND TRUNC(INTERNAL_FUNCTION("TO_DATE"))>=TRUNC(TRUNC(SYSDATE#!)))
17 - filter("C"."FROM_DATE"<=TRUNC(SYSDATE#!) AND "C"."TO_DATE">=TRUNC(SYSDATE#!))
18 - access("C"."MBR_SID"="E"."MBR_SID" AND "C"."IDNTFR_TYPE_CID"=423 AND "C"."OPRTNL_FLAG"='A')
19 - filter("MAI"."OPRTNL_FLAG"='A' AND "MAI"."STATUS_CID"=2 AND "MAI"."FROM_DATE"<=TRUNC(SYSDATE#!) AND
"MAI"."TO_DATE">=TRUNC(SYSDATE#!))
20 - access("C"."MBR_SID"="MAI"."MBR_SID")
21 - access("UAXOU"."USER_ACCT_SID"=1)
22 - filter("UAXOU"."ORG_UNIT_SID"="MAI"."ORG_UNIT_SID" AND "UAXOU"."OPRTNL_FLAG"='A' AND
"UAXOU"."FROM_DATE"<=SYSDATE#! AND "UAXOU"."TO_DATE">=SYSDATE#!)
This is output of query from v$parameter
NAME | VALUE
compatible | 12.2.0
optimizer_adaptive_plans | TRUE
optimizer_adaptive_reporting_only | FALSE
optimizer_features_enable | 12.2.0.1
This is the explain plan after adding GATHER_PLAN_STATISTICS showing the actual cardinality values:
Plan hash value: 2272581586
-------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.01 | 0 |
| 1 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 |
| 2 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 3 | TABLE ACCESS BY INDEX ROWID BATCHED| TBL_5 | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 4 | INDEX RANGE SCAN | XIF1TBL_5 | 0 | 8 | 0 |00:00:00.01 | 0 |
|* 5 | INDEX UNIQUE SCAN | XPKSTATUS | 0 | 1 | 0 |00:00:00.01 | 0 |
| 6 | TABLE ACCESS BY INDEX ROWID | STATUS | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 7 | COUNT STOPKEY | | 1 | | 0 |00:00:00.01 | 0 |
| 8 | VIEW | | 1 | 169 | 0 |00:00:00.01 | 0 |
| 9 | NESTED LOOPS | | 1 | 169 | 0 |00:00:00.01 | 0 |
| 10 | NESTED LOOPS | | 1 | 11904 | 0 |00:00:00.01 | 0 |
| 11 | NESTED LOOPS | | 1 | 62 | 0 |00:00:00.01 | 0 |
| 12 | NESTED LOOPS | | 1 | 45 | 0 |00:00:00.01 | 0 |
| 13 | NESTED LOOPS | | 1 | 33 | 0 |00:00:00.01 | 0 |
|* 14 | TABLE ACCESS BY INDEX ROWID | PROGRAM | 1 | 5 | 1 |00:00:00.01 | 2 |
| 15 | INDEX FULL SCAN | XAK1OWCP_PROGRAM | 1 | 2 | 2 |00:00:00.01 | 1 |
|* 16 | TABLE ACCESS FULL | TBL_2 | 1 | 20 | 0 |00:00:00.01 | 0 |
|* 17 | TABLE ACCESS BY INDEX ROWID | TBL_1 | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 18 | INDEX RANGE SCAN | TUNE_WS_19NOV10_X2 | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 19 | TABLE ACCESS BY INDEX ROWID | TBL_3 | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 20 | INDEX RANGE SCAN | XIE2_TBL_3 | 0 | 3 | 0 |00:00:00.01 | 0 |
|* 21 | INDEX RANGE SCAN | XIF3TBL_4 | 0 | 192 | 0 |00:00:00.01 | 0 |
|* 22 | TABLE ACCESS BY INDEX ROWID | TBL_4 | 0 | 3 | 0 |00:00:00.01 | 0 |
-------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(("MS"."STATUS_TYPE_CID"=7 AND "MS"."OPRTNL_FLAG"='A' AND "MS"."TO_DATE">=SYSDATE#! AND
"MS"."FROM_DATE"<=SYSDATE#!))
4 - access("MBR_SID"=:B1)
5 - access("S"."STATUS_TYPE_CID"=7 AND "S"."STATUS_CID"="MS"."STATUS_CID")
7 - filter(ROWNUM<102)
14 - filter("PR"."OPRTNL_FLAG"='A')
16 - filter(("E"."PROGRAM_CODE"="PR"."PROGRAM_CODE" AND "E"."OPRTNL_FLAG"='A' AND "E"."STATUS_CID"=2 AND
"E"."FROM_DATE"<=TRUNC(SYSDATE#!) AND "E"."TO_DATE">=TRUNC(SYSDATE#!)))
17 - filter(("C"."FROM_DATE"<=TRUNC(SYSDATE#!) AND "C"."TO_DATE">=TRUNC(SYSDATE#!)))
18 - access("C"."MBR_SID"="E"."MBR_SID" AND "C"."IDNTFR_TYPE_CID"=423 AND "C"."OPRTNL_FLAG"='A')
19 - filter(("MAI"."OPRTNL_FLAG"='A' AND "MAI"."STATUS_CID"=2 AND "MAI"."FROM_DATE"<=TRUNC(SYSDATE#!) AND
"MAI"."TO_DATE">=TRUNC(SYSDATE#!)))
20 - access("C"."MBR_SID"="MAI"."MBR_SID")
21 - access("UAXOU"."USER_ACCT_SID"=1)
22 - filter(("UAXOU"."ORG_UNIT_SID"="MAI"."ORG_UNIT_SID" AND "UAXOU"."OPRTNL_FLAG"='A' AND
"UAXOU"."FROM_DATE"<=SYSDATE#! AND "UAXOU"."TO_DATE">=SYSDATE#!))
I've tried various hints USE_HASH(c e) and various other combinations, none worked.
One interesting observation, if I comment the condition:
--AND uaxou.user_acct_sid = 1
The results came in 7 seconds. (Obviously, data is returned in this case).
So, what's causing the query to take so long when no data is returned? (i.e. this condition is not commented AND uaxou.user_acct_sid = 1)
I let the slow query to finish, it took 10 min 46 seconds. No data is returned
Here is the explain plan. I don't know why A-Time doesn't match with actual execution time.
Plan hash value: 2272581586
-------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.01 | 0 |
| 1 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 |
| 2 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 3 | TABLE ACCESS BY INDEX ROWID BATCHED| TBL_5 | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 4 | INDEX RANGE SCAN | XIF1TBL_5 | 0 | 8 | 0 |00:00:00.01 | 0 |
|* 5 | INDEX UNIQUE SCAN | XPKSTATUS | 0 | 1 | 0 |00:00:00.01 | 0 |
| 6 | TABLE ACCESS BY INDEX ROWID | STATUS | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 7 | COUNT STOPKEY | | 1 | | 0 |00:00:00.01 | 0 |
| 8 | VIEW | | 1 | 169 | 0 |00:00:00.01 | 0 |
| 9 | NESTED LOOPS | | 1 | 169 | 0 |00:00:00.01 | 0 |
| 10 | NESTED LOOPS | | 1 | 11904 | 0 |00:00:00.01 | 0 |
| 11 | NESTED LOOPS | | 1 | 62 | 0 |00:00:00.01 | 0 |
| 12 | NESTED LOOPS | | 1 | 45 | 0 |00:00:00.01 | 0 |
| 13 | NESTED LOOPS | | 1 | 33 | 0 |00:00:00.01 | 0 |
|* 14 | TABLE ACCESS BY INDEX ROWID | PROGRAM | 1 | 5 | 1 |00:00:00.01 | 2 |
| 15 | INDEX FULL SCAN | XAK1OWCP_PROGRAM | 1 | 2 | 2 |00:00:00.01 | 1 |
|* 16 | TABLE ACCESS FULL | TBL_2 | 1 | 20 | 0 |00:00:00.01 | 0 |
|* 17 | TABLE ACCESS BY INDEX ROWID | TBL_1 | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 18 | INDEX RANGE SCAN | TUNE_WS_19NOV10_X2 | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 19 | TABLE ACCESS BY INDEX ROWID | TBL_3 | 0 | 1 | 0 |00:00:00.01 | 0 |
|* 20 | INDEX RANGE SCAN | XIE2_TBL_3 | 0 | 3 | 0 |00:00:00.01 | 0 |
|* 21 | INDEX RANGE SCAN | XIF3TBL_4 | 0 | 192 | 0 |00:00:00.01 | 0 |
|* 22 | TABLE ACCESS BY INDEX ROWID | TBL_4 | 0 | 3 | 0 |00:00:00.01 | 0 |
-------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(("MS"."STATUS_TYPE_CID"=7 AND "MS"."OPRTNL_FLAG"='A' AND "MS"."TO_DATE">=SYSDATE#! AND
"MS"."FROM_DATE"<=SYSDATE#!))
4 - access("MBR_SID"=:B1)
5 - access("S"."STATUS_TYPE_CID"=7 AND "S"."STATUS_CID"="MS"."STATUS_CID")
7 - filter(ROWNUM<102)
14 - filter("PR"."OPRTNL_FLAG"='A')
16 - filter(("E"."PROGRAM_CODE"="PR"."PROGRAM_CODE" AND "E"."OPRTNL_FLAG"='A' AND "E"."STATUS_CID"=2 AND
"E"."FROM_DATE"<=TRUNC(SYSDATE#!) AND "E"."TO_DATE">=TRUNC(SYSDATE#!)))
17 - filter(("C"."FROM_DATE"<=TRUNC(SYSDATE#!) AND "C"."TO_DATE">=TRUNC(SYSDATE#!)))
18 - access("C"."MBR_SID"="E"."MBR_SID" AND "C"."IDNTFR_TYPE_CID"=423 AND "C"."OPRTNL_FLAG"='A')
19 - filter(("MAI"."OPRTNL_FLAG"='A' AND "MAI"."STATUS_CID"=2 AND "MAI"."FROM_DATE"<=TRUNC(SYSDATE#!) AND
"MAI"."TO_DATE">=TRUNC(SYSDATE#!)))
20 - access("C"."MBR_SID"="MAI"."MBR_SID")
21 - access("UAXOU"."USER_ACCT_SID"=1)
22 - filter(("UAXOU"."ORG_UNIT_SID"="MAI"."ORG_UNIT_SID" AND "UAXOU"."OPRTNL_FLAG"='A' AND
"UAXOU"."FROM_DATE"<=SYSDATE#! AND "UAXOU"."TO_DATE">=SYSDATE#!))

Adaptive plans may improve the execution plan.
You tagged the question as 12c but it looks like the execution plan is not using adaptive plans for some reason. Adaptive plans let Oracle change operations at run time, such as switching between NESTED LOOPS and HASH JOINS.
NESTED LOOPS are good for a small percentage of rows, and HASH JOINS are good for a large percentage of rows. Since the ROWS estimates are all small, but the query runs for three minutes, I would guess the optimizer is significantly underestimating the cardinality of the expressions and joins, and is using too many NESTED LOOPs.
If adaptive plans were enabled the execution plan should have this at the bottom:
Note
-----
- this is an adaptive plan
Since that Note is missing, I would guess there is a parameter issue on your database preventing adaptive plans. Run the below query and see if one of the features is turned off, or if the features are set to a version lower than 12:
select name, value
from v$parameter
where name in (
'optimizer_adaptive_features', --12.1 only
'optimizer_adaptive_plans', --12.2+
'optimizer_adaptive_reporting_only',
'optimizer_features_enable',
'compatible'
)
order by 1;
EDIT 1
I'm not sure why adaptive plans aren't working for you. If nobody can figure that out, then we'll need to investigate the execution plan actual values to find out precisely which operations are slow.
There are at least two ways to get the actual numbers. If you can change and re-run the offending query, you can use the hint GATHER_PLAN_STATISTICS.
--Run slow query and wait for it to finish:
select /*+ gather_plan_statistics */ * from dual;
--Find the SQL_ID of the query using some distinctive text:
select *
from v$sql
where lower(sql_fulltext) like '%gather_plan_statistics%';
--Generate execution plan with actual values.
select *
from table(dbms_xplan.display_cursor(sql_id => 'SQL_ID from above', format=>'allstats last'));
If you cannot alter the query, you can use SQL Monitor reports to find the actual values. (This feature requires Enterprise Edition and a tuning pack license.)
--Generate SQL Monitoring Report:
select dbms_sqltune.report_sql_monitor(sql_id => 'SQL_ID from above') from dual;
EDIT 2
Are you 100% sure you've found the right SQL_ID? You might want to double check GV$SQL. Sometimes the case is switched, if the SQL is submitted from an application or PL/SQL block. And rarely the real SQL statement will age out of GV$SQL, if someone runs alter system flush shared_pool;, or stats are gathered, or if you wait too long.
If that is truly the right execution plan, no time is spent on the query. Normally this means that time must be spent by the network sending the results, or the application processing the results. But since there are no rows returned a network or application issue doesn't sound likely.
If the time is spent on the database, but not on that query, then I would guess it's either a parsing issue or a recursive query issue. Parsing issues can be found by tracing, but those are caused by extremely unusual problems or queries, and likely isn't the case here.
Perhaps one of the queries Oracle uses to gather metadata is taking too long. For many queries, Oracle needs to run other queries that check privileges, dynamic sampling, etc. You may need to tune one of those other queries, and the below statements can help with that painful process:
--Clear existing run times (be careful running this on production).
--(This won't flush queries that are actively running.)
alter system flush shared_pool;
--Run your slow SQL statement here.
--...
--Now look for anything "weird" that has taken up most of the time.
select elapsed_time/1000000 seconds, gv$sql.*
from gv$sql
order by seconds desc;

Related

Oracle SQL - VIEW PUSHED PREDICATE not happening when using dblink

I'm having performance issues executing the following query (Q1):
select
z_out.*,
a_out.id
from orders a_out, test z_out
where a_out.id=z_out.id and a_out.created>trunc(sysdate) and rownum<10
Table orders contains millions of rows; orders.id is the primary key and orders.craeted is indexed.
The view is:
create or replace view test as
select/*+qb_name(q_outer)*/
id,
min(value) keep (dense_rank first order by id) as value
from (
select/*+qb_name(q_inner)*/
id,
case
when substr(id, -1)<'5'
--and exists(select 1 from dual#db2)
then 'YYY'
end as attr_1
from orders a1
) a2, small_table b2
where b2.attr_1 in (nvl(a2.attr_1, '#'), '*')
group by id
where small_table b2 contains about 200 records (all the columns are varchar2).
Executing Q1 has great performances and the following execution plan:
Plan hash value: 2906430222
-----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 274 | 64 (0)| 00:00:01 | | |
|* 1 | COUNT STOPKEY | | | | | | | |
| 2 | NESTED LOOPS | | 1 | 274 | 64 (0)| 00:00:01 | | |
| 3 | PARTITION LIST ALL | | 1 | 22 | 59 (0)| 00:00:01 | 1 | 2 |
| 4 | PARTITION RANGE ALL | | 1 | 22 | 59 (0)| 00:00:01 | 1 | LAST |
| 5 | TABLE ACCESS BY LOCAL INDEX ROWID| ORDERS | 1 | 22 | 59 (0)| 00:00:01 | 1 | 29 |
|* 6 | INDEX RANGE SCAN | IDX_ORDERS_CREATED | 1 | | 57 (0)| 00:00:01 | 1 | 29 |
| 7 | VIEW PUSHED PREDICATE | TEST | 1 | 252 | 5 (0)| 00:00:01 | | |
|* 8 | FILTER | | | | | | | |
| 9 | SORT AGGREGATE | | 1 | 55 | | | | |
| 10 | NESTED LOOPS | | 259 | 14245 | 5 (0)| 00:00:01 | | |
|* 11 | INDEX UNIQUE SCAN | PK_ID | 1 | 14 | 2 (0)| 00:00:01 | | |
|* 12 | INDEX STORAGE FAST FULL SCAN | IDX_MN_AN_AD_ALL | 259 | 10619 | 3 (0)| 00:00:01 | | |
-----------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<10)
6 - access("A_OUT"."CREATED">TRUNC(SYSDATE#!))
8 - filter(COUNT(*)>0)
11 - access("ID"="A_OUT"."ID")
12 - storage("B2"."ATTR_1"=NVL(CASE WHEN SUBSTR("ID",(-1))<'5' THEN 'YYY' END ,'#') OR "B2"."ATTR_1"='*')
filter("B2"."ATTR_1"=NVL(CASE WHEN SUBSTR("ID",(-1))<'5' THEN 'YYY' END ,'#') OR "B2"."ATTR_1"='*')
Q1 performance issues happen when the line --and exists(select 1 from dual#db2) in the view is uncommented.
The new execution plan is:
Plan hash value: 3271081243
----------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | Inst |IN-OUT|
----------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 288 | 5273K (1)| 00:03:27 | | | | |
|* 1 | COUNT STOPKEY | | | | | | | | | |
|* 2 | HASH JOIN | | 1 | 288 | 5273K (1)| 00:03:27 | | | | |
| 3 | JOIN FILTER CREATE | :BF0000 | 1 | 22 | 59 (0)| 00:00:01 | | | | |
| 4 | PARTITION LIST ALL | | 1 | 22 | 59 (0)| 00:00:01 | 1 | 2 | | |
| 5 | PARTITION RANGE ALL | | 1 | 22 | 59 (0)| 00:00:01 | 1 | LAST | | |
| 6 | TABLE ACCESS BY LOCAL INDEX ROWID| ORDERS | 1 | 22 | 59 (0)| 00:00:01 | 1 | 29 | | |
|* 7 | INDEX RANGE SCAN | IDX_ORDERS_CREATED | 1 | | 57 (0)| 00:00:01 | 1 | 29 | | |
| 8 | VIEW | TEST | 3840K| 974M| 5273K (1)| 00:03:27 | | | | |
| 9 | SORT GROUP BY | | 3840K| 201M| 5273K (1)| 00:03:27 | | | | |
| 10 | JOIN FILTER USE | :BF0000 | 994M| 50G| 5273K (1)| 00:03:27 | | | | |
| 11 | NESTED LOOPS | | 994M| 50G| 5273K (1)| 00:03:27 | | | | |
| 12 | INDEX FULL SCAN | PK_ID | 3840K| 51M| 66212 (1)| 00:00:03 | | | | |
|* 13 | INDEX STORAGE FAST FULL SCAN | IDX_MN_AN_AD_ALL | 259 | 10619 | 1 (0)| 00:00:01 | | | | |
| 14 | REMOTE | | | | | | | | DB2 | R->S |
----------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<10)
2 - access("A_OUT"."ID"="Z_OUT"."ID")
7 - access("A_OUT"."CREATED">TRUNC(SYSDATE#!))
13 - filter("B2"."ATTR_1"=NVL(CASE WHEN (SUBSTR("ID",(-1))<'5' AND EXISTS (SELECT 0 FROM "A1")) THEN 'YYY' END ,'#') OR
"B2"."ATTR_1"='*')
Remote SQL Information (identified by operation id):
----------------------------------------------------
14 - EXPLAIN PLAN INTO PLAN_TABLE#! FOR SELECT 0 FROM "DUAL" "A1" (accessing 'DB2' )
I would like the view to be accessed n times, like in the first scenario.
I tried using hints but didn't succeed.
May be useful to say that even with the line and exists(select 1 from dual#db2) uncommented in the view, the following query has great performances (I know that is different from Q1).
select
(select value from test z_out where a_out.id=z_out.id) as value,
a_out.id
from orders a_out
where a_out.created>trunc(sysdate) and rownum<10
So, I guess the view works fine when it's accessed n times even if the line and exists(select 1 from dual#db2) is uncommented. But I'm not being able to force the execution plan in that direction.
If hints are necessary, I'd like to add them inside the view DDL only (if possible) so that who uses the view won't have to worry about it.
================================================================
Edit: the following were executed:
alter session set statistics_level = 'ALL';
-- Q1 (the query I'm having problems with)
select * from table (dbms_xplan.display_cursor (format=>'ALLSTATS LAST'));
Plan hash value: 3271081243
------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.01 | 0 | 0 | | | |
|* 1 | COUNT STOPKEY | | 1 | | 0 |00:00:00.01 | 0 | 0 | | | |
|* 2 | HASH JOIN | | 1 | 1 | 0 |00:00:00.01 | 0 | 0 | 3789K| 3789K| 1078K (0)|
| 3 | JOIN FILTER CREATE | :BF0000 | 1 | 1 | 25602 |00:00:00.22 | 23345 | 161 | | | |
| 4 | PARTITION LIST ALL | | 1 | 1 | 25602 |00:00:00.21 | 23345 | 161 | | | |
| 5 | PARTITION RANGE ALL | | 2 | 1 | 25602 |00:00:00.21 | 23345 | 161 | | | |
| 6 | TABLE ACCESS BY LOCAL INDEX ROWID| ORDERS | 29 | 1 | 25602 |00:00:00.20 | 23345 | 161 | | | |
|* 7 | INDEX RANGE SCAN | IDX_CREATED | 13 | 1 | 25602 |00:00:00.12 | 474 | 161 | 1025K| 1025K| |
| 8 | VIEW | TEST | 1 | 3820K| 0 |00:00:00.01 | 0 | 0 | | | |
| 9 | SORT GROUP BY | | 1 | 3820K| 0 |00:00:00.01 | 0 | 0 | 73728 | 73728 | |
| 10 | JOIN FILTER USE | :BF0000 | 1 | 989M| 106M|00:03:38.87 | 60M| 52960 | | | |
| 11 | NESTED LOOPS | | 1 | 989M| 328M|00:03:04.11 | 60M| 52960 | | | |
| 12 | INDEX FULL SCAN | PK_ID | 1 | 3820K| 1245K|00:00:21.04 | 200K| 52959 | 1025K| 1025K| |
|* 13 | INDEX STORAGE FAST FULL SCAN | IDX_MN_AN_AD_ALL | 1245K| 259 | 328M|00:02:12.09 | 60M| 1 | 1025K| 1025K| |
| 14 | REMOTE | | 1 | | 1 |00:00:00.01 | 0 | 0 | | | |
------------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<10)
2 - access("A_OUT"."ID"="Z_OUT"."ID")
7 - access("A_OUT"."CREATED">TRUNC(SYSDATE#!))
13 - filter(("B2"."ATTR_1"=NVL(CASE WHEN (SUBSTR("ID",(-1))<'5' AND IS NOT NULL) THEN 'YYY' END ,'#') OR "B2"."ATTR_1"='*'))
Note: Q1 performances prevent the query to complete if and exists(select 1 from dual#db2) in the view is uncommented. To get the previous execution plan I had to alter the session, run Q1, stop Q1 (after about 4 minutes) and then calculate the plan.
The following execution plan was generated the same way, but the view had the line --and exists(select 1 from dual#db2) commented (performances were good).
Plan hash value: 2906430222
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 9 |00:00:00.01 | 223 |
|* 1 | COUNT STOPKEY | | 1 | | 9 |00:00:00.01 | 223 |
| 2 | NESTED LOOPS | | 1 | 1 | 9 |00:00:00.01 | 223 |
| 3 | PARTITION LIST ALL | | 1 | 1 | 9 |00:00:00.01 | 41 |
| 4 | PARTITION RANGE ALL | | 1 | 1 | 9 |00:00:00.01 | 41 |
| 5 | TABLE ACCESS BY LOCAL INDEX ROWID| ORDERS | 14 | 1 | 9 |00:00:00.01 | 41 |
|* 6 | INDEX RANGE SCAN | IDX_CREATED | 12 | 1 | 9 |00:00:00.01 | 33 |
| 7 | VIEW PUSHED PREDICATE | TEST | 9 | 1 | 9 |00:00:00.01 | 182 |
|* 8 | FILTER | | 9 | | 9 |00:00:00.01 | 182 |
| 9 | SORT AGGREGATE | | 9 | 1 | 9 |00:00:00.01 | 182 |
| 10 | NESTED LOOPS | | 9 | 259 | 2376 |00:00:00.01 | 182 |
|* 11 | INDEX UNIQUE SCAN | PK_ID | 9 | 1 | 9 |00:00:00.01 | 20 |
|* 12 | INDEX STORAGE FAST FULL SCAN | IDX_MN_AN_AD_ALL | 9 | 259 | 2376 |00:00:00.01 | 162 |
-----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<10)
6 - access("A_OUT"."CREATED">TRUNC(SYSDATE#!))
8 - filter(COUNT(*)>0)
11 - access("ID"="A_OUT"."ID")
12 - storage(("B2"."ATTR_1"=NVL(CASE WHEN SUBSTR("ID",(-1))<'5' THEN 'YYY' END ,'#') OR
"B2"."ATTR_1"='*'))
filter(("B2"."ATTR_1"=NVL(CASE WHEN SUBSTR("ID",(-1))<'5' THEN 'YYY' END ,'#') OR
"B2"."ATTR_1"='*'))

Oracle SQL indexed query 100% cpu usage

I'm running a relatively simple query
SELECT * FROM confirm_v c
JOIN person p ON c.created_by=p.id
INNER JOIN invoice_confirm ic ON ic.confirm_id=c.id
WHERE c.id = (SELECT id FROM
(SELECT c2.id FROM confirm c2
JOIN invoice_confirm ic2 ON ic2.confirm_id=c2.id
WHERE ic2.invoice_id=11954081
AND c2.previous=0
AND c2.canceled=0
AND c2.confirm_type='INVOICE'
ORDER BY c2.id)
WHERE rownum=1);
which results in 100% cpu usage by the rdb. The confirm_type is a varchar2(50 char), the rest are number(10) if it means anything.
The invoice_confirm and confirm tables are covered by indices and there are no full table scans visible in the execution plan for this query.
This query isn't executed a lot, but accounts for nearly 100% of total cpu usage. Any ideas are appreciated.
EDIT:
The explain plan in text from for the query.
EXPLAIN PLAN FOR ...
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
Plan hash value: 1705859247
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 69 | 10 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 69 | 10 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 69 | 10 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 1 | 57 | 7 (0)| 00:00:01 |
| 4 | NESTED LOOPS | | 1 | 30 | 5 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | CONFIRM | 1 | 24 | 3 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_CONFIRM | 1 | | 2 (0)| 00:00:01 |
|* 7 | COUNT STOPKEY | | | | | |
| 8 | VIEW | | 4 | 52 | 27 (4)| 00:00:01 |
|* 9 | SORT ORDER BY STOPKEY | | 4 | 132 | 27 (4)| 00:00:01 |
| 10 | NESTED LOOPS | | 4 | 132 | 26 (0)| 00:00:01 |
| 11 | NESTED LOOPS | | 11 | 132 | 26 (0)| 00:00:01 |
| 12 | TABLE ACCESS BY INDEX ROWID BATCHED| INVOICE_CONFIRM | 3 | 36 | 4 (0)| 00:00:01 |
|* 13 | INDEX RANGE SCAN | FKI_INVOICE_CONFIRM_INVOICE | 2 | | 3 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | PK_CONFIRM | 1 | | 1 (0)| 00:00:01 |
|* 15 | TABLE ACCESS BY INDEX ROWID | CONFIRM | 1 | 21 | 2 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | FKI_INVOICE_CONFIRM_CONFIRM | 1 | 6 | 2 (0)| 00:00:01 |
| 17 | TABLE ACCESS BY INDEX ROWID | PERSON | 1 | 27 | 2 (0)| 00:00:01 |
|* 18 | INDEX UNIQUE SCAN | PK_KASUTAJA | 1 | | 1 (0)| 00:00:01 |
|* 19 | INDEX RANGE SCAN | FKI_INVOICE_CONFIRM_CONFIRM | 1 | | 2 (0)| 00:00:01 |
| 20 | TABLE ACCESS BY INDEX ROWID | INVOICE_CONFIRM | 1 | 12 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("CONFIRM"."ID"= (SELECT "ID" FROM (SELECT "C2"."ID" "ID" FROM "INVOICE_CONFIRM" "IC2","CONFIRM" "C2"
WHERE "IC2"."CONFIRM_ID"="C2"."ID" AND "C2"."CANCELED"=0 AND "C2"."PREVIOUS"=0 AND "C2"."CONFIRM_TYPE"='INVOICE' AND
"IC2"."INVOICE_ID"=11954081 ORDER BY "C2"."ID") "from$_subquery$_006" WHERE ROWNUM=1))
7 - filter(ROWNUM=1)
9 - filter(ROWNUM=1)
13 - access("IC2"."INVOICE_ID"=11954081)
14 - access("IC2"."CONFIRM_ID"="C2"."ID")
15 - filter("C2"."CANCELED"=0 AND "C2"."PREVIOUS"=0 AND "C2"."CONFIRM_TYPE"='INVOICE')
16 - access("IC"."CONFIRM_ID"="CONFIRM"."ID")
18 - access("CONFIRM"."CREATED_BY"="P"."ID")
19 - access("IC"."CONFIRM_ID"="CONFIRM"."ID")
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- 2 Sql Plan Directives used for this statement
Gather optimizer statistics on the relevant tables and investigate why the statistics were missing.
begin
dbms_stats.gather_table_stats(user, 'CONFIRM');
dbms_stats.gather_table_stats(user, 'INVOICE_CONFIRM');
dbms_stats.gather_table_stats(user, 'PERSON');
end;
/
Optimizer statistics are critical for Oracle to achieve good performance. The note dynamic statistics used: dynamic sampling (level=2) implies that there are tables with missing optimizer statistics. That should never happen unless the tables were created within the last day.
Oracle automatically gathers stale and missing statistics. Check if the job is running with this query. If there are no recent rows, ask your DBA to re-enable the task.
select *
from dba_optstat_operations
where operation like '%auto%'
order by start_time desc;
The autotask is good enough for most tables. But if there's a large batch process that updates a lot of rows then the statistics should be manually collected as soon as the job is complete.

IN clause causing high execution time

I have a 118 line query similar to this:
select * from (The inner query with many joins) WHERE campus_code IN ('560','598')
The campus_code is getting generated by a function f_get_bookstore(SSBSECT_TERM_CODE,SSBSECT_CRN) AS SSBSECT_CAMP_CODE in the inner query. If I run the inner query alone its count is 18 & it is getting executed in 13 s. But if I add the WHERE campus_code IN ('560','598') then it is taking more than 2 min.
Another strange thing is, I have another query which is also like
select * from (The inner query with many joins) WHERE campus_code IN ('560','598'). Here the inner query slightly different than previous one. The inner query is fast & returning 92 rows. But here the campus_code IN filtering is fast even though it is working on 92 rows (unlike 18 rows for the previous query). Here also the campus_code is generated through the same function.
Can any body help to tune the query? Please tell what more info do you need.
This is the entire query:
SELECT *
FROM
(SELECT 'columbusstate' bk_institution_id,
'columbusstate.'
|| scbcrse_subj_code
|| '.'
|| scbcrse_crse_numb
||'.'
|| Ssbsect_Crn
|| '.'
|| ssbsect_term_code bk_section_id,
ssbsect_camp_code AS campus_code,
scbcrse_subj_code
|| '.'
|| scbcrse_crse_numb
||'.'
|| Ssbsect_Crn
|| '.'
|| ssbsect_term_code institution_section_id,
ssbsect_crn short_description,
scbcrse_title AS description,
ssbsect_crn sections_ssbsect_crn,
ssbsect_term_code sections_ssbsect_term_code,
'na' instructor_first_name,
'na' instructor_last_name,
scbcrse_subj_code
|| '.'
|| scbcrse_crse_numb rel_institution_course_id,
scbcrse_title AS rel_course_description,
scbcrse_title AS rel_course_name,
scbcrse_crse_numb AS course_short_desc,
scbcrse_crse_numb course_number,
stvterm_desc term_short_desc,
stvterm_code rel_institution_term_id,
section.ssbsect_crn,
ssbsect_ssts_code AS ssbsect_ssts_code,
'columbusstate.'
|| stvterm_code rel_bk_term_id,
'columbusstate.'
|| scbcrse_subj_code
|| '.'
|| scbcrse_crse_numb rel_bk_course_id,
ssbsect_seq_numb,
ssbsect_enrl ssbsect_enrl,
ssbsect_enrl estimated_enrl,
ssbsect_max_enrl ssbsect_max_enrl,
ssbsect_crn ssbsect_section_key,
ssbsect_crn ssbsect_section_number,
'parent' relationship,
course.scbcrse_subj_code institution_department_id ,
'DFLT' institution_division_id,
'DFLT' division_short_desc
FROM
(SELECT *
FROM
(SELECT SSBSECT_TERM_CODE,
SSBSECT_CRN,
SSBSECT_SUBJ_CODE,
SSBSECT_CRSE_NUMB,
SSBSECT_PTRM_CODE,
SSBSECT_SEQ_NUMB,
SSBSECT_SSTS_CODE,
SSBSECT_MAX_ENRL,
SSBSECT_ENRL,
SSBSECT_PRNT_IND,
f_get_bookstore(SSBSECT_TERM_CODE,SSBSECT_CRN) AS SSBSECT_CAMP_CODE
FROM SSBSECT
) sect
JOIN
(SELECT *
FROM
(SELECT * FROM saturn.stvterm WHERE STVTERM_CODE >= '201401'
)
) term
ON term.stvterm_code=sect.ssbsect_term_code
) section
JOIN
(SELECT C1.scbcrse_subj_code,
C1.scbcrse_dept_code,
C1.scbcrse_crse_numb,
C1.scbcrse_title
FROM saturn.scbcrse C1
LEFT JOIN saturn.scbcrse C2
ON (C1.scbcrse_subj_code = C2.scbcrse_subj_code
AND C1.scbcrse_crse_numb = C2.scbcrse_crse_numb
AND C1.scbcrse_eff_term < C2.scbcrse_eff_term)
WHERE c2.scbcrse_eff_term IS NULL
) Course ON Course.scbcrse_subj_code = Section.ssbsect_subj_code
AND scbcrse_crse_numb = section.ssbsect_crse_numb
AND ssbsect_ssts_code IN ('A','V','X')
LEFT JOIN
(SELECT sirasgn_term_code sirasgn_term_code,
sirasgn_crn,
MAX(spriden_pidm) spriden_pidm,
MAX(spriden_first_name) instructor_first_name,
MAX(spriden_last_name) instructor_last_name
FROM
(SELECT Pidm spriden_pidm,
Csu_Id SPRIDEN_ID,
First_Name spriden_first_name,
Last_Name spriden_last_name,
Mi spriden_mi,
External_User_Id login,
Email
FROM Csuapps.Wfollett_Person
) persons
JOIN
( SELECT * FROM saturn.sirasgn WHERE SIRASGN_PRIMARY_IND = 'Y'
) relations
ON persons.spriden_pidm=relations.sirasgn_pidm
GROUP BY sirasgn_crn,
sirasgn_term_code
) instr ON section.ssbsect_term_code=instr.sirasgn_term_code
AND section.ssbsect_crn =instr.sirasgn_crn
WHERE Course.scbcrse_subj_code = 'ACCT'
AND section.ssbsect_term_code = '201702'
)
WHERE campus_code IN ('560','1157')
Execution Plan:
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2063389120
-----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 77 | 968K| | 4364 (3)| 00:00:01 |
| 1 | SORT ORDER BY | | 77 | 968K| 624K| 4364 (3)| 00:00:01 |
|* 2 | VIEW | | 77 | 968K| | 4155 (3)| 00:00:01 |
| 3 | COUNT | | | | | | |
| 4 | VIEW | | 77 | 967K| | 4155 (3)| 00:00:01 |
| 5 | SORT ORDER BY | | 77 | 774K| | 4155 (3)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|* 6 | FILTER | | | | | | |
|* 7 | HASH JOIN RIGHT OUTER | | 77 | 774K| | 4154 (3)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | SCBCRSE_KEY_INDEX | 83 | 1494 | | 1 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | 77 | 772K| | 4153 (3)| 00:00:01 |
| 10 | NESTED LOOPS OUTER | | 23 | 229K| | 4139 (3)| 00:00:01 |
|* 11 | HASH JOIN OUTER | | 23 | 1656 | | 3783 (1)| 00:00:01 |
| 12 | NESTED LOOPS | | 23 | 1334 | | 7 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID | STVTERM | 1 | 22 | | 1 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | PK_STVTERM | 1 | | | 1 (0)| 00:00:01 |
|* 15 | TABLE ACCESS BY INDEX ROWID BATCHED| SSBSECT | 23 | 828 | | 6 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | SSBSECT_INDEX_SUBJ | 25 | | | 1 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 17 | VIEW | | 2172 | 30408 | | 3775 (1)| 00:00:01 |
| 18 | HASH GROUP BY | | 2172 | 8537K| 16M| 3775 (1)| 00:00:01 |
|* 19 | HASH JOIN | | 4166 | 15M| | 1364 (1)| 00:00:01 |
| 20 | VIEW | VW_GBF_14 | 2312 | 18496 | | 211 (1)| 00:00:01 |
| 21 | HASH GROUP BY | | 2312 | 48552 | | 211 (1)| 00:00:01 |
|* 22 | TABLE ACCESS FULL | SIRASGN | 2312 | 48552 | | 210 (1)| 00:00:01 |
| 23 | VIEW | WFOLLETT_PERSON | 3714 | 14M| | 1153 (1)| 00:00:01 |
| 24 | SORT UNIQUE | | 3714 | 342K| | 1153 (1)| 00:00:01 |
| 25 | UNION-ALL | | | | | | |
| 26 | NESTED LOOPS | | 1 | 59 | | 2 (0)| 00:00:01 |
| 27 | NESTED LOOPS | | 1 | 59 | | 2 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|* 28 | INDEX RANGE SCAN | PK_GLBEXTR | 1 | 38 | | 1 (0)| 00:00:01 |
|* 29 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
| 30 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
| 31 | NESTED LOOPS | | 1912 | 130K| | 605 (0)| 00:00:01 |
| 32 | NESTED LOOPS | | 1912 | 130K| | 605 (0)| 00:00:01 |
|* 33 | HASH JOIN | | 1912 | 93688 | | 31 (0)| 00:00:01 |
| 34 | VIEW | VW_SQ_2 | 3076 | 83052 | | 10 (0)| 00:00:01 |
| 35 | HASH GROUP BY | | 3076 | 39988 | | 10 (0)| 00:00:01 |
| 36 | INDEX FULL SCAN | PK_SIBINST | 6243 | 81159 | | 10 (0)| 00:00:01 |
|* 37 | TABLE ACCESS FULL | SIBINST | 3881 | 85382 | | 21 (0)| 00:00:01 |
|* 38 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 39 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
| 40 | NESTED LOOPS | | 1801 | 41423 | | 543 (1)| 00:00:01 |
| 41 | NESTED LOOPS | | 1801 | 41423 | | 543 (1)| 00:00:01 |
| 42 | VIEW | VW_DTP_6100A9C4 | 1801 | 3602 | | 3 (34)| 00:00:01 |
| 43 | HASH UNIQUE | | 1801 | 23413 | | 3 (34)| 00:00:01 |
|* 44 | INDEX RANGE SCAN | PK_SIRASGN | 4161 | 54093 | | 2 (0)| 00:00:01 |
|* 45 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
| 46 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
| 47 | VIEW PUSHED PREDICATE | | 1 | 10165 | | 16 (25)| 00:00:01 |
|* 48 | FILTER | | | | | | |
| 49 | NESTED LOOPS | | 1 | 10164 | | 16 (25)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 50 | NESTED LOOPS | | 1 | 79 | | 4 (0)| 00:00:01 |
|* 51 | FILTER | | | | | | |
| 52 | NESTED LOOPS OUTER | | 1 | 60 | | 3 (0)| 00:00:01 |
| 53 | NESTED LOOPS | | 1 | 42 | | 2 (0)| 00:00:01 |
| 54 | TABLE ACCESS BY INDEX ROWID | SSBSECT | 1 | 24 | | 1 (0)| 00:00:01 |
|* 55 | INDEX UNIQUE SCAN | PK_SSBSECT | 1 | | | 1 (0)| 00:00:01 |
|* 56 | INDEX RANGE SCAN | SCBCRSE_KEY_INDEX | 1 | 18 | | 1 (0)| 00:00:01 |
|* 57 | INDEX RANGE SCAN | SCBCRSE_KEY_INDEX | 15046 | 264K| | 1 (0)| 00:00:01 |
|* 58 | INDEX RANGE SCAN | PK_SIRASGN | 1 | 19 | | 1 (0)| 00:00:01 |
| 59 | VIEW | WFOLLETT_PERSON | 1 | 10085 | | 12 (34)| 00:00:01 |
| 60 | SORT UNIQUE | | 3 | 304 | | 12 (34)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 61 | UNION ALL PUSHED PREDICATE | | | | | | |
| 62 | NESTED LOOPS | | 1 | 59 | | 2 (0)| 00:00:01 |
| 63 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
|* 64 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
|* 65 | INDEX RANGE SCAN | PK_GLBEXTR | 1 | 38 | | 1 (0)| 00:00:01 |
| 66 | NESTED LOOPS | | 1 | 70 | | 3 (0)| 00:00:01 |
| 67 | NESTED LOOPS | | 1 | 70 | | 3 (0)| 00:00:01 |
| 68 | NESTED LOOPS | | 1 | 48 | | 2 (0)| 00:00:01 |
| 69 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
|* 70 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
| 71 | VIEW | VW_SQ_1 | 1 | 27 | | 1 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 72 | SORT GROUP BY | | 1 | 13 | | 1 (0)| 00:00:01 |
|* 73 | INDEX RANGE SCAN | PK_SIBINST | 2 | 26 | | 1 (0)| 00:00:01 |
|* 74 | INDEX UNIQUE SCAN | PK_SIBINST | 1 | | | 1 (0)| 00:00:01 |
|* 75 | TABLE ACCESS BY INDEX ROWID | SIBINST | 1 | 22 | | 1 (0)| 00:00:01 |
| 76 | NESTED LOOPS | | 1 | 23 | | 4 (25)| 00:00:01 |
| 77 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
|* 78 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
|* 79 | VIEW | VW_DTP_32C68FB6 | 1 | 2 | | 3 (34)| 00:00:01 |
| 80 | SORT UNIQUE | | 2 | 26 | | 3 (34)| 00:00:01 |
|* 81 | INDEX RANGE SCAN | PK_SIRASGN | 2 | 26 | | 2 (0)| 00:00:01 |
| 82 | TABLE ACCESS BY INDEX ROWID BATCHED | SCBCRSE | 3 | 126 | | 1 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|* 83 | INDEX RANGE SCAN | SCBCRSE_KEY_INDEX | 1 | | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("from$_subquery$_002"."CAMPUS_CODE"='1157' OR "from$_subquery$_002"."CAMPUS_CODE"='560') AND "R">=1
AND "R"<=1500)
6 - filter("C2"."SCBCRSE_EFF_TERM" IS NULL)
7 - access("C1"."SCBCRSE_SUBJ_CODE"="C2"."SCBCRSE_SUBJ_CODE"(+) AND
"C1"."SCBCRSE_CRSE_NUMB"="C2"."SCBCRSE_CRSE_NUMB"(+))
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
filter("C1"."SCBCRSE_EFF_TERM"<"C2"."SCBCRSE_EFF_TERM"(+))
8 - access("C2"."SCBCRSE_SUBJ_CODE"(+)='ACCT')
11 - access("SSBSECT_TERM_CODE"="INSTR"."SIRASGN_TERM_CODE"(+) AND "SSBSECT_CRN"="INSTR"."SIRASGN_CRN"(+))
14 - access("STVTERM"."STVTERM_CODE"='201702')
15 - filter("SSBSECT_SSTS_CODE"='A' OR "SSBSECT_SSTS_CODE"='V' OR "SSBSECT_SSTS_CODE"='X')
16 - access("SSBSECT_SUBJ_CODE"='ACCT' AND "SSBSECT_TERM_CODE"='201702')
filter("SSBSECT_TERM_CODE"='201702')
19 - access("PIDM"="ITEM_1")
22 - filter("SIRASGN"."SIRASGN_TERM_CODE"='201702' AND "SIRASGN_PRIMARY_IND"='Y')
28 - access("GLBEXTR_APPLICATION"='STUDENT' AND "GLBEXTR_SELECTION"='CURR_ENRL' AND "GLBEXTR_CREATOR_ID"='GSHOUL')
29 - access("GOBTPAC_PIDM"=TO_NUMBER("GLBEXTR_KEY"))
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
33 - access("A"."SIBINST_TERM_CODE_EFF"="MAX(B.SIBINST_TERM_CODE_EFF)" AND "ITEM_2"="A"."SIBINST_PIDM")
37 - filter("A"."SIBINST_FCST_CODE"='AC' AND "A"."SIBINST_FCTG_CODE"<>'EMPL')
38 - access("A"."SIBINST_PIDM"="GOBTPAC_PIDM")
44 - access("SIRASGN_TERM_CODE">="TOOLS"."GETTERMCODE"(NULL,SYSDATE#!))
45 - access("ITEM_1"="GOBTPAC_PIDM")
48 - filter("SSBSECT_TERM_CODE">='201602' AND "SSBSECT_TERM_CODE"='201702')
51 - filter("C2"."SCBCRSE_EFF_TERM" IS NULL)
55 - access("SSBSECT_TERM_CODE"="SSBSECT_TERM_CODE" AND "SSBSECT_CRN"="SSBSECT_CRN")
filter("SSBSECT_TERM_CODE"='201702')
56 - access("SSBSECT_SUBJ_CODE"="C1"."SCBCRSE_SUBJ_CODE" AND "SSBSECT_CRSE_NUMB"="C1"."SCBCRSE_CRSE_NUMB")
57 - access("C1"."SCBCRSE_SUBJ_CODE"="C2"."SCBCRSE_SUBJ_CODE"(+) AND
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
"C1"."SCBCRSE_CRSE_NUMB"="C2"."SCBCRSE_CRSE_NUMB"(+) AND "C1"."SCBCRSE_EFF_TERM"<"C2"."SCBCRSE_EFF_TERM"(+) AND
"C2"."SCBCRSE_EFF_TERM"(+) IS NOT NULL)
58 - access("REL"."SIRASGN_TERM_CODE"="SSBSECT_TERM_CODE" AND "REL"."SIRASGN_CRN"="SSBSECT_CRN")
filter("REL"."SIRASGN_TERM_CODE"="SSBSECT_TERM_CODE" AND "REL"."SIRASGN_TERM_CODE"='201702' AND
"REL"."SIRASGN_CRN"="SSBSECT_CRN")
64 - access("GOBTPAC_PIDM"="REL"."SIRASGN_PIDM")
65 - access("GLBEXTR_APPLICATION"='STUDENT' AND "GLBEXTR_SELECTION"='CURR_ENRL' AND "GLBEXTR_CREATOR_ID"='GSHOUL')
filter(TO_NUMBER("GLBEXTR_KEY")="REL"."SIRASGN_PIDM" AND "GOBTPAC_PIDM"=TO_NUMBER("GLBEXTR_KEY"))
70 - access("GOBTPAC_PIDM"="REL"."SIRASGN_PIDM")
73 - access("B"."SIBINST_PIDM"="REL"."SIRASGN_PIDM")
74 - access("A"."SIBINST_PIDM"="REL"."SIRASGN_PIDM" AND "A"."SIBINST_TERM_CODE_EFF"="MAX(B.SIBINST_TERM_CODE_EFF)")
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
filter("A"."SIBINST_PIDM"="GOBTPAC_PIDM" AND "ITEM_1"="A"."SIBINST_PIDM")
75 - filter("A"."SIBINST_FCST_CODE"='AC' AND "A"."SIBINST_FCTG_CODE"<>'EMPL')
78 - access("GOBTPAC_PIDM"="REL"."SIRASGN_PIDM")
79 - filter("ITEM_1"="GOBTPAC_PIDM")
81 - access("SIRASGN_TERM_CODE">="TOOLS"."GETTERMCODE"(NULL,SYSDATE#!) AND "SIRASGN_PIDM"="REL"."SIRASGN_PIDM")
filter("SIRASGN_PIDM"="REL"."SIRASGN_PIDM")
83 - access("C1"."SCBCRSE_SUBJ_CODE"='ACCT' AND "C1"."SCBCRSE_CRSE_NUMB"="SSBSECT_CRSE_NUMB")
139 rows selected.
The performance of your query depends on the details, that we don't know, and on the joins. In general, if the joins result in a huge set of rows, that will eat a lot of cpu and ram. So try to add where clauses that minimize the number of rows in the joins.
Said in an other way, just imagine you are the cpu. Go through your query and try to estimate the number of rows that you need to process, and how you could limit that number of rows.
Are you using an index on crucial tables to speed up selects? Are you modifying the search column used in an index, so that the index does not work? Stuff like this is very important.
Good luck!
update:
The plan shows to me that most cpu is burned for the outermost query, something that you already noticed in the timing measurements. My strategy would be to try to move the outermost where-clause towards the inner queries. If the database engine can apply the where-clause in an earlier phase, the query will need less memory and cpu.
Now it is not possible to see to which table each output field belongs. If I where you I would give EVERY table in each FROM an alias.
For the sake of testing performance, and for posting here, you could simplify the lists of output fields. Leave out fields that are not required by outer queries, or use asterisk. Also, try to present a perfectly pretty printed query.
Apart from the Plan, could you get some info on memory usage? With the outer query, perhaps it needs to get a lot of data in memory before outputting results. Just imagine if this results in exhausting ram and needs swap, that will cost a lot of time. Memory use may also come from holding a lock on possibly big tables, so do not get fooled by your 'just 18 rows' of output.
OK, I'm going to put this in a "answer", since comments seem to be ignored.
The only way to know what is going on and how to fix your problem is to get the execution plan. Otherwise every answer is a guess. You may get lucky that a guess works, but then you will never know why. So please help us to help you.
To get an execution plan (for both the queries with and without the WHERE clause), run this after your query...
set lines 500
set pages 10000
select * from table( dbms_xplan.display_cursor( null, null, 'TYPICAL' ));
Is campus_code an integer? If it is, try removing the apostrophes, like this:
WHERE campus_code IN (560,598)
Otherwise, each value gets converted before being compared, and that can take a lot of time.
Hope this helps.
What you observe is by 99% a merging predicates in an inline view.
This works typically fine and helps performance as illustrated on an example below.
Sample Data
create table T1 as
select 'xxxx'||rownum crampus_code from dual connect by level <= 100000;
create index idx1 on t1(crampus_code);
This query can take a substantial time on a large table as the whole table must be accessed.
select crampus_code, count(*) from T1 group by crampus_code;
A following query using the previous query as a subquery can be very effective. How?
The WHERE clause in MERGE in the subquery and only the data for the two keys are accessed (index) and aggregated.
with agg as
(
select
a.crampus_code, count(*)
from
T1 a
group by
crampus_code
)
select *
from agg
where crampus_code in ('xxxx42','xxxx399');
The proof is in the execution plan (that you don't provided)
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 48 | 3 (0)| 00:00:01 |
| 1 | SORT GROUP BY NOSORT| | 2 | 48 | 3 (0)| 00:00:01 |
| 2 | INLIST ITERATOR | | | | | |
|* 3 | INDEX RANGE SCAN | IDX1 | 2 | 48 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("A"."CRAMPUS_CODE"='xxxx399' OR
"A"."CRAMPUS_CODE"='xxxx42')
You see the table is accesse via index for only the two keys.
Your Case
This is only speculation but IMO during the merge predicate phase you get a much worst execution plan that without it.
This explain the increase in elapsed time by addin the WHERE clause.
Only if you show both plans (subquery and the query with WHERE) you can be sure...
Workaround
So what can you do if the predicate merge destroys the performance?
Simple turn it off. Unfortunately you must use an undocumented hint MATERIALIZE, that set up the result of the query as temporary table
and the WHERE predicate will be applied on it.
This should work for your 18 rows. I'm not sure, but thing you must rewrite query using the subquery factoring (WITH).
with agg as
(select /*+ MATERIALIZE */ a.crampus_code, count(*) from T1 a group by crampus_code)
select * from agg
where crampus_code in ('xxxx42','xxxx399');
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 97325 | 3516K| 94 (5)| 00:00:02 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D673A_CE046F62 | | | | |
| 3 | HASH GROUP BY | | 97325 | 2281K| 41 (10)| 00:00:01 |
| 4 | TABLE ACCESS FULL | T1 | 97325 | 2281K| 37 (0)| 00:00:01 |
|* 5 | VIEW | | 97325 | 3516K| 54 (2)| 00:00:01 |
| 6 | TABLE ACCESS FULL | SYS_TEMP_0FD9D673A_CE046F62 | 97325 | 2281K| 54 (2)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - filter("CRAMPUS_CODE"='xxxx399' OR "CRAMPUS_CODE"='xxxx42')

Need help to optimize Oracle query in 12c

This particular query was working fine till we were in 11i but as soon as we switched to 12c the query has been doing really bad.
I tried to remove the hint and it seems to be doing little better but our DBA wants us to remove all the multiple subqueries which cause serialization of the various sub-steps. I am at a loss on how to change it.
Any pointers on what I can do or start with?
WITH
-- Get all active accounts that have not been suspended and the suspension rules
-- apply for the account
TT1 AS (SELECT
pl.employer_id,
ma.employee_id,
ma.member_account_id,
pl.plan_id
FROM sa_plans pl,
sa_accounts ma
WHERE TRUNC(SYSDATE) BETWEEN pl.start_date AND NVL(pl.end_date, TRUNC(SYSDATE))
AND pl.employer_id = 23
AND pl.plan_type_id NOT IN (4
,1)
AND pl.plan_id = ma.plan_id
AND sa_mc_info.fn_ee_susp_exempt(ma.employee_id, DECODE(pl.plan_type_id, 1, 6 ,5 )) = 0
AND p_outstanding_threshold_perc > 0
AND NVL(ma.auto_suspension_flag, 0) = 0
AND TRUNC(SYSDATE) BETWEEN ma.account_effective_date AND NVL(ma.account_end_date, TRUNC(SYSDATE))
AND ma.account_effective_date != NVL(ma.account_end_date, ma.account_effective_date + 1)
),
-- Get all accounts that were active during the plan year for the current accounts
-- and the outstanding transactions
TT2 AS (SELECT /*+ MATERIALIZE */
ma1.member_account_id,
ma1.plan_id,
ma1.employee_id ,
wwsa.sa_mc_info.fn_acnt_unverified_txns(ma1.member_account_id) outstd_amount
FROM sa_accounts ma1,
TT1 ma
WHERE ma1.account_effective_date != NVL(ma1.account_end_date, ma1.account_effective_date + 1)
AND ma1.plan_id = ma.plan_id
AND ma1.employee_id = ma.employee_id
AND ma1.member_account_id = TT1.member_account_id),
-- Sum the outstanding transactions for the EE and plan
TT3 AS (SELECT /*+ MATERIALIZE ORDERED */
TT1.member_account_id,
SUM(TT2.outstd_amount) outstd_amount
FROM TT1,
TT2
WHERE TT1.employee_id = TT2.employee_id
AND TT1.plan_id = TT2.plan_id
GROUP BY TT1.member_account_id
HAVING SUM(TT2.outstd_amount) > 0),
-- Get the current account balance for accounts with outstanding transactions
TT4 AS (SELECT /*+ MATERIALIZE ORDERED */
TT1.*,
sa_bal_info.fn_account_balance(TT1.member_account_id) balance,
TT3.outstd_amount
FROM TT1,
TT3
WHERE TT1.member_account_id = TT3.member_account_id),
-- Get the list of accounts that need to be suspended
TT5 as (SELECT /*+ MATERIALIZE */
member_account_id,
employee_id
FROM TT4
WHERE outstd_amount > balance * p_outstanding_threshold_perc
AND outstd_amount > NVL(p_minimum_threshold_amount, 0) )
SELECT *
FROM TT5
ORDER BY employee_id;
This is the explain plan
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 8622 (1)| 00:00:01 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D666F_DCBC1560 | | | | |
| 3 | NESTED LOOPS | | 4 | 252 | 8600 (1)| 00:00:01 |
| 4 | NESTED LOOPS | | 1707 | 252 | 8600 (1)| 00:00:01 |
|* 5 | TABLE ACCESS BY INDEX ROWID BATCHED| SA_PLANS | 3 | 84 | 8452 (1)| 00:00:01 |
| 6 | INDEX FULL SCAN | SA_PLANS_PK | 19218 | | 75 (2)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | SA_ACCOUNTS_N03 | 569 | | 2 (0)| 00:00:01 |
|* 8 | TABLE ACCESS BY INDEX ROWID | SA_ACCOUNTS | 1 | 35 | 67 (0)| 00:00:01 |
| 9 | LOAD AS SELECT | SYS_TEMP_0FD9D6670_DCBC1560 | | | | |
| 10 | NESTED LOOPS | | 3 | 177 | 8 (0)| 00:00:01 |
| 11 | NESTED LOOPS | | 3 | 177 | 8 (0)| 00:00:01 |
| 12 | VIEW | | 1 | 26 | 2 (0)| 00:00:01 |
| 13 | TABLE ACCESS FULL | SYS_TEMP_0FD9D666F_DCBC1560 | 1 | 22 | 2 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | SA_ACCOUNTS_N01 | 3 | | 2 (0)| 00:00:01 |
|* 15 | TABLE ACCESS BY INDEX ROWID | SA_ACCOUNTS | 3 | 99 | 6 (0)| 00:00:01 |
| 16 | LOAD AS SELECT | SYS_TEMP_0FD9D6671_DCBC1560 | | | | |
|* 17 | FILTER | | | | | |
| 18 | HASH GROUP BY | | 1 | 41 | 5 (20)| 00:00:01 |
|* 19 | HASH JOIN | | 1 | 41 | 4 (0)| 00:00:01 |
| 20 | VIEW | | 1 | 17 | 2 (0)| 00:00:01 |
| 21 | TABLE ACCESS FULL | SYS_TEMP_0FD9D666F_DCBC1560 | 1 | 22 | 2 (0)| 00:00:01 |
| 22 | VIEW | | 1 | 24 | 2 (0)| 00:00:01 |
| 23 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6670_DCBC1560 | 1 | 30 | 2 (0)| 00:00:01 |
| 24 | LOAD AS SELECT | SYS_TEMP_0FD9D6672_DCBC1560 | | | | |
|* 25 | HASH JOIN | | 1 | 78 | 4 (0)| 00:00:01 |
| 26 | VIEW | | 1 | 52 | 2 (0)| 00:00:01 |
| 27 | TABLE ACCESS FULL | SYS_TEMP_0FD9D666F_DCBC1560 | 1 | 22 | 2 (0)| 00:00:01 |
| 28 | VIEW | | 1 | 26 | 2 (0)| 00:00:01 |
| 29 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6671_DCBC1560 | 1 | 19 | 2 (0)| 00:00:01 |
| 30 | LOAD AS SELECT | SYS_TEMP_0FD9D6673_DCBC1560 | | | | |
|* 31 | VIEW | | 1 | 52 | 2 (0)| 00:00:01 |
| 32 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6672_DCBC1560 | 1 | 48 | 2 (0)| 00:00:01 |
| 33 | SORT ORDER BY | | 1 | 26 | 3 (34)| 00:00:01 |
| 34 | VIEW | | 1 | 26 | 2 (0)| 00:00:01 |
| 35 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6673_DCBC1560 | 1 | 12 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------
Try to execute TT1 and evaluate execution time. If it's OK, then continue with TT1+TT2 and so on. You need to understand where problem is before truing to solve it.
I would assume your problem is directed related to a bad plan.
So, as you said, it performed just fine on 11g database so there basic two things you could do to try to solve your problem in a short term manner:
Check the optimizer_features_enable parameter on 12c version. If it is set to 12.* or an upper version, try to downgrade the session who is running the query to the 11.* version of your old database.
Assuming you have Tuning Pack (licensing issues - take care) enabled into your production environment, you could use SQL Profiles. How? You could manually copy your the plan from the 11g and import it to the 12c database. Take a look at dbms_sqltune.import_sql_profile.
https://oracle-randolf.blogspot.com.br/2009/03/plan-stability-in-10g-using-existing.html
As I said before, these are short term action. It would be better to evaluate your SQL.

Sql tuning using table and view

I'm having a big performance problem with the following query. And need help to make it as fast as possible.
VIEW_SHIPMENT_ORDER_RELEASE got 2 million rows and I'm sure that I can make a better query to speed this. The application is taking almost 2 minutes to run.
SELECT O.ORDER_RELEASE_GID
FROM ORDER_RELEASE O, ORDER_RELEASE_STATUS S
WHERE O.ORDER_RELEASE_GID = S.ORDER_RELEASE_GID
AND S.STATUS_TYPE_GID = 'STATUS'
AND S.STATUS_VALUE_GID IN ('OPEN', 'OPEN-HANDLE')
AND O.SOURCE_LOCATION_GID = '114'
AND O.ORDER_RELEASE_GID NOT IN
(SELECT V.ORDER_RELEASE_GID FROM VIEW_SHIPMENT_ORDER_RELEASE V
WHERE V.ORDER_RELEASE_GID = O.ORDER_RELEASE_GID)
Here's the view code:
create or replace view glogowner.view_shipment_order_release as
select distinct shp.perspective, shp.shipment_gid, ssul.order_release_gid
from shipment shp,
shipment_s_equipment_join ssej,
s_equipment_s_ship_unit_join sessuj,
s_ship_unit_line ssul
where shp.shipment_gid = ssej.shipment_gid
and ssej.s_equipment_gid = sessuj.s_equipment_gid
and sessuj.s_ship_unit_gid = ssul.s_ship_unit_gid
and ssul.order_release_gid is not null
The explain plan:
1 Plan hash value: 1257125198
2
3 --------------------------------------------------------------------------------------------------------------------------------------
4 | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Inst |
5 --------------------------------------------------------------------------------------------------------------------------------------
6 | 0 | SELECT STATEMENT REMOTE | | 314 | 98596 | | 35795 (1)| 00:07:10 | |
7 | 1 | NESTED LOOPS | | | | | | | |
8 | 2 | NESTED LOOPS | | 314 | 98596 | | 35795 (1)| 00:07:10 | |
9 |* 3 | HASH JOIN ANTI | | 201 | 48441 | | 35192 (1)| 00:07:03 | |
10 | 4 | TABLE ACCESS BY INDEX ROWID | ORDER_RELEASE | 20104 | 726K| | 3893 (1)| 00:00:47 | ABC123 |
11 |* 5 | INDEX RANGE SCAN | OR_SOURCE_LOCATION_GID | 20104 | | | 157 (0)| 00:00:02 | ABC123 |
12 | 6 | VIEW | VW_SQ_1 | 1515K| 294M| | 31293 (1)| 00:06:16 | ABC123 |
13 |* 7 | HASH JOIN | | 1515K| 144M| | 31293 (1)| 00:06:16 | |
14 | 8 | INDEX STORAGE FAST FULL SCAN | IND_SSEJ_SEQUIPGID | 69218 | 811K| | 91 (0)| 00:00:02 | ABC123 |
15 |* 9 | HASH JOIN | | 1515K| 127M| 73M| 31195 (1)| 00:06:15 | |
16 | 10 | INDEX STORAGE FAST FULL SCAN| PK_S_EQUIPMENT_S_SHIP_UNIT_JOI | 1515K| 56M| | 3958 (1)| 00:00:48 | ABC123 |
17 |* 11 | TABLE ACCESS STORAGE FULL | S_SHIP_UNIT_LINE | 1619K| 75M| | 18893 (1)| 00:03:47 | ABC123 |
18 |* 12 | INDEX UNIQUE SCAN | PK_ORDER_RELEASE_STATUS | 1 | | | 2 (0)| 00:00:01 | ABC123 |
19 |* 13 | TABLE ACCESS BY INDEX ROWID | ORDER_RELEASE_STATUS | 2 | 146 | | 3 (0)| 00:00:01 | ABC123 |
20 --------------------------------------------------------------------------------------------------------------------------------------
21
22 Predicate Information (identified by operation id):
23 ---------------------------------------------------
24
25 3 - access("A2"."ORDER_RELEASE_GID"="ORDER_RELEASE_GID")
26 5 - access("A2"."SOURCE_LOCATION_GID"='114')
27 7 - access("SSEJ"."S_EQUIPMENT_GID"="SESSUJ"."S_EQUIPMENT_GID")
28 9 - access("SESSUJ"."S_SHIP_UNIT_GID"="SSUL"."S_SHIP_UNIT_GID")
29 11 - storage("SSUL"."ORDER_RELEASE_GID" IS NOT NULL)
30 filter("SSUL"."ORDER_RELEASE_GID" IS NOT NULL)
31 12 - access("A2"."ORDER_RELEASE_GID"="A1"."ORDER_RELEASE_GID" AND "A1"."STATUS_TYPE_GID"='STATUS')
32 13 - filter("A1"."STATUS_VALUE_GID"='OPEN' OR "A1"."STATUS_VALUE_GID"='OPEN-HANDLE')
I'd make sure that the following are indexed:
shipment.shipment_gid
shipment_s_equipment_join.s_equipment_gid
s_equipment_s_ship_unit_join.s_ship_unit_gid
s_ship_unit_line.order_release_gid
The NOT IN might work better as a NOT EXISTS.