Oracle first N rows of a group using RANK running too slow - oracle

I have a table with below columns
Table{
load_date DATE
effective_date DATE
Application_ID Varchar2
Datasource_id VARCHAR2
Rule_id Varchar2
Entity_Id varchar2
Rule_status number
batch_execution_ts TIMESTAMP
}
Now I have a query to fetch results as below
select * from (
select rank() over (partition by effective_date, rule_id, entity_id order by batch_execution_ts desc) as rank,
s.*
from TABLE s
where s.load_date between :date1 and :date2
and s.effective_date between :effdate1 and :effdate2
and application_id=:appid
and datasource_id=:dsid) result
where result.rank=1
We have a query requirement to send results in max od 3seconds.. but this query is running for whopping 4 mins and no results returned. TABLE is partitioned on "load_date"and we have LOCAL INDEX created on effective_date, application_id, datasource_id, rule_id, entity_id
Any suggestion on improving performance. FYI.. each load_date partition contains around 2-3 million rows. Running parallel is not helping the performance either.
Added EXPLAIN PLAN below.
Plan hash value: 2095006046
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 20720 | 425 (1)| 00:00:01 | | | | | |
|* 1 | PX COORDINATOR | | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | 8 | 20720 | 425 (1)| 00:00:01 | | | Q1,01 | P->S | QC (RAND) |
|* 3 | VIEW | | 8 | 20720 | 425 (1)| 00:00:01 | | | Q1,01 | PCWP | |
|* 4 | WINDOW SORT PUSHED RANK | | 8 | 12776 | 425 (1)| 00:00:01 | | | Q1,01 | PCWP | |
| 5 | PX RECEIVE | | 8 | 12776 | 425 (1)| 00:00:01 | | | Q1,01 | PCWP | |
| 6 | PX SEND HASH | :TQ10000 | 8 | 12776 | 425 (1)| 00:00:01 | | | Q1,00 | P->P | HASH |
|* 7 | WINDOW CHILD PUSHED RANK | | 8 | 12776 | 425 (1)| 00:00:01 | | | Q1,00 | PCWP | |
|* 8 | FILTER | | | | | | | | Q1,00 | PCWC | |
| 9 | NESTED LOOPS OUTER | | 8 | 12776 | 424 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 10 | PX PARTITION RANGE ITERATOR | | 8 | 2576 | 422 (0)| 00:00:01 | KEY | KEY | Q1,00 | PCWC | |
| 11 | TABLE ACCESS BY LOCAL INDEX ROWID| DQM_ENTITY_RULE_STATUS | 8 | 2576 | 422 (0)| 00:00:01 | KEY | KEY | Q1,00 | PCWP | |
|* 12 | INDEX RANGE SCAN | NU_DQM_ERS_IDX_4 | 27 | | 421 (0)| 00:00:01 | KEY | KEY | Q1,00 | PCWP | |
| 13 | VIEW PUSHED PREDICATE | | 1 | 1275 | 7 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 14 | NESTED LOOPS OUTER | | 1 | 757 | 7 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 15 | NESTED LOOPS OUTER | | 1 | 725 | 6 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 16 | NESTED LOOPS | | 1 | 711 | 5 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 17 | NESTED LOOPS | | 1 | 614 | 4 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 18 | NESTED LOOPS | | 1 | 511 | 3 (0)| 00:00:01 | | | Q1,00 | PCWP | |
|* 19 | TABLE ACCESS BY INDEX ROWID | DQM_RULE | 1 | 479 | 2 (0)| 00:00:01 | | | Q1,00 | PCWP | |
|* 20 | INDEX UNIQUE SCAN | PK_DQM_RULE | 1 | | 1 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 21 | TABLE ACCESS BY INDEX ROWID | DQM_FW_DQ_DIM | 1 | 32 | 1 (0)| 00:00:01 | | | Q1,00 | PCWP | |
|* 22 | INDEX UNIQUE SCAN | PK_DQM_FW_DQ_DIM | 1 | | 0 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 23 | TABLE ACCESS BY INDEX ROWID | DQM_RULE_FUNCTION | 1 | 103 | 1 (0)| 00:00:01 | | | Q1,00 | PCWP | |
|* 24 | INDEX UNIQUE SCAN | PK_DQM_RULE_FUNCTION | 1 | | 0 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 25 | TABLE ACCESS BY INDEX ROWID | DQM_RULE_GRP | 1 | 97 | 1 (0)| 00:00:01 | | | Q1,00 | PCWP | |
|* 26 | INDEX UNIQUE SCAN | PK_DQM_RULE_GRP | 1 | | 0 (0)| 00:00:01 | | | Q1,00 | PCWP | |
|* 27 | INDEX FULL SCAN | PK_DQM_FW_DQ_DIM_HRCHY | 1 | 14 | 1 (0)| 00:00:01 | | | Q1,00 | PCWP | |
| 28 | TABLE ACCESS BY INDEX ROWID | DQM_FW_DQ_DIM | 1 | 32 | 1 (0)| 00:00:01 | | | Q1,00 | PCWP | |
|* 29 | INDEX UNIQUE SCAN | PK_DQM_FW_DQ_DIM | 1 | | 0 (0)| 00:00:01 | | | Q1,00 | PCWP | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_DATE(:EFFECTIVEDATETO)>=TO_DATE(:EFFECTIVEDATEFROM) AND TO_DATE(:LOADDATETO)>=TO_DATE(:LOADDATEFROM))
3 - filter("LATEST_EXCEPTION"=1)
4 - filter(RANK() OVER ( PARTITION BY "S"."EFFECTIVE_DT","S"."VENDOR_ENTITY_KEY","S"."RULE_ID" ORDER BY INTERNAL_FUNCTION("S"."BATCH_EXECUTION_TS")
DESC )<=1)
7 - filter(RANK() OVER ( PARTITION BY "S"."EFFECTIVE_DT","S"."VENDOR_ENTITY_KEY","S"."RULE_ID" ORDER BY INTERNAL_FUNCTION("S"."BATCH_EXECUTION_TS")
DESC )<=1)
8 - filter(TO_DATE(:EFFECTIVEDATETO)>=TO_DATE(:EFFECTIVEDATEFROM) AND TO_DATE(:LOADDATETO)>=TO_DATE(:LOADDATEFROM))
12 - access("S"."EFFECTIVE_DT">=:EFFECTIVEDATEFROM AND "S"."LOAD_DT">=:LOADDATEFROM AND "S"."APPLICATION_ID"=SYS_OP_C2C(:SOURCEID) AND
"S"."DATA_SOURCE_ID"=SYS_OP_C2C(:VENDORID) AND "S"."EFFECTIVE_DT"<=:EFFECTIVEDATETO AND "S"."LOAD_DT"<=:LOADDATETO)
filter("S"."LOAD_DT">=:LOADDATEFROM AND "S"."LOAD_DT"<=:LOADDATETO AND "S"."DATA_SOURCE_ID"=SYS_OP_C2C(:VENDORID) AND
"S"."APPLICATION_ID"=SYS_OP_C2C(:SOURCEID))
19 - filter("RULETABLE"."FUNC_ID" IS NOT NULL AND "RULETABLE"."RULE_GRP_ID" IS NOT NULL)
20 - access("RULETABLE"."RULE_ID"="S"."RULE_ID")
22 - access("DIM"."DIMENSION_ID"="RULETABLE"."DIMENSION_ID")
24 - access("RULETABLE"."FUNC_ID"="RULEFUNCTIONTABLE"."FUNC_ID")
26 - access("RGRP"."RULE_GRP_ID"="RULETABLE"."RULE_GRP_ID")
27 - access("SUB_DIM"."SUB_DIMENSION_ID"(+)="DIM"."DIMENSION_ID")
filter("SUB_DIM"."SUB_DIMENSION_ID"(+)="DIM"."DIMENSION_ID")
29 - access("DIM1"."DIMENSION_ID"(+)="SUB_DIM"."DIMENSION_ID")
Note
-----
- dynamic sampling used for this statement (level=6)
- Degree of Parallelism is 32 because of hint

Related

oracle query taking more execution time in oracle when i m using AND condition

This below query taking more execution time when in filtering with AND Condition TD.A97 = '4408' ,and apart from them I m joining two table and two synonyms can u help me to reduce execution time for this query.
SELECT DISTINCT TC.CUS_ACNT_NBR ,
TC.CUS_ACNT_ROLE_CD ,
TD.F_DOCNUMBER,
TD.A45,
HD.SHPMNT_NBR,
HD.SHPMNT_ID
FROM TDOC_CUS_ACNT TC
INNER JOIN TDOC TD ON TD.F_DOCNUMBER = TC.F_DOCNUMBER
INNER JOIN DWH_SHIPMENT_DIM HD ON TD.A45 = HD.SHPMNT_NBR
INNER JOIN DWH_INVOICE_CHARGE_FACT ICF ON HD.shpmnt_dim_key = ICF.shipment_dim_fk
WHERE TC.CUS_ACNT_ROLE_CD in ('BILL','SHPR','THRD')
AND TD.A97 = '4408' ;
One way you can use to reduce execution time is to use parallel hints in your query.
ALTER TABLE T PARALLEL 4;
SELECT /*+ parallel(4) */ DISTINCT TC.CUS_ACNT_NBR ...
oracle docs
explain plan:below my explain plan with with AND condition.
PLAN_TABLE_OUTPUT
Plan hash value: 53520552
----------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | TQ/Ins |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1639K| 148M| | 15382 (1)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10007 | 1639K| 148M| | 15382 (1)| 00:00:01 | Q1,07 | P->S | QC (RAND) |
| 3 | HASH UNIQUE | | 1639K| 148M| 164M| 15382 (1)| 00:00:01 | Q1,07 | PCWP | |
| 4 | PX RECEIVE | | 1639K| 148M| | 15382 (1)| 00:00:01 | Q1,07 | PCWP | |
| 5 | PX SEND HASH | :TQ10006 | 1639K| 148M| | 15382 (1)| 00:00:01 | Q1,06 | P->P | HASH |
| 6 | HASH UNIQUE | | 1639K| 148M| 164M| 15382 (1)| 00:00:01 | Q1,06 | PCWP | |
|* 7 | HASH JOIN | | 1639K| 148M| | 12902 (1)| 00:00:01 | Q1,06 | PCWP | |
| 8 | PX RECEIVE | | 434K| 33M| | 8351 (1)| 00:00:01 | Q1,06 | PCWP | |
| 9 | PX SEND HASH | :TQ10005 | 434K| 33M| | 8351 (1)| 00:00:01 | Q1,05 | P->P | HASH |
|* 10 | HASH JOIN BUFFERED | | 434K| 33M| | 8351 (1)| 00:00:01 | Q1,05 | PCWP | |
| 11 | BUFFER SORT | | | | | | | Q1,05 | PCWC | |
| 12 | PX RECEIVE | | 325K| 7636K| | 2335 (1)| 00:00:01 | Q1,05 | PCWP | |
| 13 | PX SEND HASH | :TQ10001 | 325K| 7636K| | 2335 (1)| 00:00:01 | | S->P | HASH |
|* 14 | TABLE ACCESS FULL | TDOC_CUS_ACNT | 325K| 7636K| | 2335 (1)| 00:00:01 | | | |
| 15 | PX RECEIVE | | 272K| 15M| | 6015 (1)| 00:00:01 | Q1,05 | PCWP | |
| 16 | PX SEND HASH | :TQ10004 | 272K| 15M| | 6015 (1)| 00:00:01 | Q1,04 | P->P | HASH |
|* 17 | HASH JOIN | | 272K| 15M| | 6015 (1)| 00:00:01 | Q1,04 | PCWP | |
| 18 | PX RECEIVE | | 268K| 5508K| | 660 (1)| 00:00:01 | Q1,04 | PCWP | |
| 19 | PX SEND HASH | :TQ10003 | 268K| 5508K| | 660 (1)| 00:00:01 | Q1,03 | P->P | HASH |
| 20 | PX BLOCK ITERATOR | | 268K| 5508K| | 660 (1)| 00:00:01 | Q1,03 | PCWC | |
|* 21 | TABLE ACCESS FULL| TDOC | 268K| 5508K| | 660 (1)| 00:00:01 | Q1,03 | PCWP | |
| 22 | BUFFER SORT | | | | | | | Q1,04 | PCWC | |
| 23 | PX RECEIVE | | 1769K| 62M| | 5354 (1)| 00:00:01 | Q1,04 | PCWP | |
| 24 | PX SEND HASH | :TQ10000 | 1769K| 62M| | 5354 (1)| 00:00:01 | | S->P | HASH |
| 25 | REMOTE | SHIPMENT_DIM | 1769K| 62M| | 5354 (1)| 00:00:01 | TDIM | R->S | |
| 26 | BUFFER SORT | | | | | | | Q1,06 | PCWC | |
| 27 | PX RECEIVE | | 6677K| 82M| | 4550 (1)| 00:00:01 | Q1,06 | PCWP | |
| 28 | PX SEND HASH | :TQ10002 | 6677K| 82M| | 4550 (1)| 00:00:01 | | S->P | HASH |
| 29 | REMOTE | INVOICE_CHARGE_FACT | 6677K| 82M| | 4550 (1)| 00:00:01 | TDIM | R->S | |
----------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
7 - access("HD"."SHPMNT_DIM_KEY"="ICF"."SHIPMENT_DIM_FK")
10 - access("TD"."F_DOCNUMBER"="TC"."F_DOCNUMBER")
14 - filter("TC"."CUS_ACNT_ROLE_CD"='BILL' OR "TC"."CUS_ACNT_ROLE_CD"='SHPR' OR "TC"."CUS_ACNT_ROLE_CD"='THRD')
17 - access("TD"."A45"="HD"."SHPMNT_NBR")
21 - filter("TD"."A45" IS NOT NULL AND "TD"."A97"='4408')
Remote SQL Information (identified by operation id):
----------------------------------------------------
25 - SELECT "SHPMNT_DIM_KEY","SHPMNT_NBR","SHPMNT_ID" FROM "DIM"."SHIPMENT_DIM" "HD" (accessing 'TDIM.WORLD' )
29 - SELECT "SHIPMENT_DIM_FK" FROM "DIM"."INVOICE_CHARGE_FACT" "ICF" (accessing 'TDIM.WORLD' )
Note
-----
- dynamic statistics used: dynamic sampling (level=5)
- Degree of Parallelism is 16 because of table property

Oracle - Do filter predicate order change the execution plan?

We are troubleshooting a performance problem - The application uses a VIEW and filter predicates applied as below. In the first case, result is retrieved in seconds,but the second one runs for more than an hour.
columns referred in the view actually point to table D. Please note that this view was written for some other purpose and now used for an enhancement(dont know why - management decision).
I can see that the problem is FTS on the partition tables E and F, but not able to understand why/how the order of predicates change the execution plan? this is a cost based approach only and statistics are upto date.
This is not a well formed query - using % eliminates indexes etc - but what puzzles me is why the plan changes when the statement is exchanging filter predicates
select COL2 from VIEW where COL3 like
'%180%' and COL4 LIKE '%Solu%'
Plan hash value: 1618822878
------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 1379K(100)| | | |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
|* 1 | FILTER | | | | | | | |
| 2 | NESTED LOOPS OUTER | | 116K| 8568K| 1077K (19)| 02:47:19 | | |
|* 3 | HASH JOIN RIGHT OUTER | | 97611 | 6481K| 266K (1)| 00:41:25 | | |
|* 4 | INDEX FAST FULL SCAN | IDX1_A | 45156 | 352K| 25 (8)| 00:00:01 | | |
| 5 | NESTED LOOPS | | 97611 | 5719K| 266K (1)| 00:41:25 | | |
| 6 | NESTED LOOPS | | 98629 | 5719K| 266K (1)| 00:41:25 | | |
| 7 | VIEW | VW_NSO_1 | 98629 | 674K| 82 (3)| 00:00:01 | | |
| 8 | HASH UNIQUE | | 98629 | 1338K| 82 (3)| 00:00:01 | | |
| 9 | UNION-ALL | | | | | | | |
| 10 | TABLE ACCESS FULL | B | 97591 | 667K| 80 (3)| 00:00:01 | | |
| 11 | TABLE ACCESS FULL | C | 1038 | 2076 | 2 (0)| 00:00:01 | | |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
|* 12 | INDEX UNIQUE SCAN | PK_D | 1 | | 2 (0)| 00:00:01 | | |
|* 13 | TABLE ACCESS BY GLOBAL INDEX ROWID| D | 1 | 53 | 3 (0)| 00:00:01 | ROWID | ROWID |
| 14 | VIEW | | 1 | 7 | 8 (25)| 00:00:01 | | |
| 15 | UNION ALL PUSHED PREDICATE | | | | | | | |
| 16 | SORT UNIQUE | | 1 | 9 | 4 (25)| 00:00:01 | | |
|* 17 | INDEX RANGE SCAN | IDX1_E | 1 | 9 | 3 (0)| 00:00:01 | | |
| 18 | SORT UNIQUE | | 1 | 9 | 5 (20)| 00:00:01 | | |
|* 19 | INDEX RANGE SCAN | F | 2 | 18 | 4 (0)| 00:00:01 | | |
|* 20 | TABLE ACCESS BY INDEX ROWID | G | 1 | 36 | 3 (0)| 00:00:01 | | |
|* 21 | INDEX UNIQUE SCAN | UK_G | 1 | | 2 (0)| 00:00:01 | | |
------------------------------------------------------------------------------------------------------------------------------------
select COL2 from VIEW where COL4 LIKE '%Solu%' AND COL3 like
'%180%' ;
Plan hash value: 2380952204
-----------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Pid | Ord | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | | 24 | SELECT STATEMENT | | | | | 2598K(100)| | | |
|* 1 | 0 | 23 | FILTER | | | | | | | | |
|* 2 | 1 | 20 | HASH JOIN OUTER | | 116K| 8568K| 7632K| 2295K (2)| 05:56:38 | | |
|* 3 | 2 | 11 | HASH JOIN OUTER | | 97611 | 6481K| 6864K| 266K (1)| 00:41:27 | | |
| 4 | 3 | 9 | NESTED LOOPS | | 97611 | 5719K| | 266K (1)| 00:41:25 | | |
| 5 | 4 | 7 | NESTED LOOPS | | 98629 | 5719K| | 266K (1)| 00:41:25 | | |
| 6 | 5 | 5 | VIEW | VW_NSO_1 | 98629 | 674K| | 82 (3)| 00:00:01 | | |
| 7 | 6 | 4 | HASH UNIQUE | | 98629 | 1338K| | 82 (3)| 00:00:01 | | |
| 8 | 7 | 3 | UNION-ALL | | | | | | | | |
| 9 | 8 | 1 | TABLE ACCESS FULL | B | 97591 | 667K| | 80 (3)| 00:00:01 | | |
| 10 | 8 | 2 | TABLE ACCESS FULL | C | 1038 | 2076 | | 2 (0)| 00:00:01 | | |
|* 11 | 5 | 6 | INDEX UNIQUE SCAN | PK_D | 1 | | | 2 (0)| 00:00:01 | | |
|* 12 | 4 | 8 | TABLE ACCESS BY GLOBAL INDEX ROWID| D | 1 | 53 | | 3 (0)| 00:00:01 | ROWID | ROWID |
|* 13 | 3 | 10 | TABLE ACCESS FULL | A | 45156 | 352K| | 75 (3)| 00:00:01 | | |
| 14 | 2 | 19 | VIEW | | 127M| 851M| | 1988K (3)| 05:08:49 | | |
| 15 | 14 | 18 | UNION-ALL | | | | | | | | |
| 16 | 15 | 14 | HASH UNIQUE | | 21M| 184M| 412M| 235K (4)| 00:36:33 | | |
| 17 | 16 | 13 | PARTITION RANGE ALL | | 21M| 184M| | 164K (4)| 00:25:30 | 1 | 32 |
| 18 | 17 | 12 | TABLE ACCESS FULL | E | 21M| 184M| | 164K (4)| 00:25:30 | 1 | 32 |
| 19 | 15 | 17 | HASH UNIQUE | | 106M| 910M| 4569M| 1752K (2)| 04:32:17 | | |
| 20 | 19 | 16 | PARTITION RANGE ALL | | 238M| 2048M| | 1286K (1)| 03:19:54 | 1 | 32 |
| 21 | 20 | 15 | TABLE ACCESS FULL | F | 238M| 2048M| | 1286K (1)| 03:19:54 | 1 | 32 |
|* 22 | 1 | 22 | TABLE ACCESS BY INDEX ROWID | G | 1 | 36 | | 3 (0)| 00:00:01 | | |
|* 23 | 22 | 21 | INDEX UNIQUE SCAN | UK_G | 1 | | | 2 (0)| 00:00:01 | | |
-----------------------------------------------------------------------------------------------------------------------------------------------------

Complicated Oracle Grouping Composite CUBE Query

I need to use the CUBE grouping function in order to get every possible combination so that this report can be used on APEX with parameters controlling how the report views. My full query is too complicated to show and will probably just confuse the situation. here I have the cutdown version
Select /*+ NO_PARALLEL */ ETP_ETPC_UID,
Decode (Grouping(ETP_ET_UID), 1, '-Grouped-', ETP_ET_UID),
/* Decode (Grouping(ETP_ET_UID), 1, '-Grouped-', ET_ABBR), */
Decode (Grouping(ETP_REFERENCE_1), 1, '-Grouped-', ETP_REFERENCE_1),
Decode (Grouping(ETP_REFERENCE_2), 1, '-Grouped-', ETP_REFERENCE_2),
Sum(ETP_COUNT)
From ETP_PROFILE,
ET_EVENT_TYPE
Where ETP_ET_UID = ET_UID
Group By
ETP_ETPC_UID,
Cube( /*(*/ETP_ET_UID/*, ET_ABBR)*/ , ETP_REFERENCE_1, ETP_REFERENCE_2)
The issue I am currently having is to do with the sections I have commented out. According to this Oracle Base article the composite column is meant to be treated as 1, so great, I can have the ET_ABBR in my query and just set ET_UID and ET_ABBR as a composite (un-comment my code and you will see).
When I do this, it seems to ridiculously increase the cost of the query (according to explain plan) and indeed it takes forever to run. If I remove my ET_ABBR column (how the code is right now with comments in place) it loads very quick and Explain plan cost is great.
Am I doing something wrong here, should I be using Grouping Sets or something like that? This is the first time I am messing with these special grouping commands, and they seem to be good, but very confusing.
EDIT:
Explain plan for Commented Query:
Plan hash value: 3169115854
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 142K| 9M| 408 (3)| 00:00:05 | | |
| 1 | SORT GROUP BY | | 142K| 9M| 408 (3)| 00:00:05 | | |
| 2 | GENERATE CUBE | | 142K| 9M| 408 (3)| 00:00:05 | | |
| 3 | SORT GROUP BY | | 142K| 9M| 408 (3)| 00:00:05 | | |
| 4 | PARTITION RANGE ALL| | 142K| 9M| 401 (1)| 00:00:05 | 1 |1048575|
| 5 | PARTITION LIST ALL| | 142K| 9M| 401 (1)| 00:00:05 | 1 | 10 |
| 6 | TABLE ACCESS FULL| ETP_PROFILE | 142K| 9M| 401 (1)| 00:00:05 | 1 |1048575|
------------------------------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Explain Plan for un-commented code:
Plan hash value: 2063641247
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 54 | 6426 | 427 (4)| 00:00:06 | | |
| 1 | TEMP TABLE TRANSFORMATION | | | | | | | |
| 2 | MULTI-TABLE INSERT | | | | | | | |
| 3 | SORT GROUP BY ROLLUP | | 54 | 4536 | 412 (3)| 00:00:05 | | |
|* 4 | HASH JOIN | | 142K| 11M| 406 (1)| 00:00:05 | | |
| 5 | TABLE ACCESS FULL | ET_EVENT_TYPE | 55 | 605 | 4 (0)| 00:00:01 | | |
| 6 | PARTITION RANGE ALL | | 142K| 9M| 401 (1)| 00:00:05 | 1 |1048575|
| 7 | PARTITION LIST ALL | | 142K| 9M| 401 (1)| 00:00:05 | 1 | 10 |
| 8 | TABLE ACCESS FULL | ETP_PROFILE | 142K| 9M| 401 (1)| 00:00:05 | 1 |1048575|
| 9 | DIRECT LOAD INTO | SYS_TEMP_0FD9D6E6F_E9BC1839 | | | | | | |
| 10 | DIRECT LOAD INTO | SYS_TEMP_0FD9D6E70_E9BC1839 | | | | | | |
| 11 | LOAD AS SELECT | SYS_TEMP_0FD9D6E70_E9BC1839 | | | | | | |
| 12 | SORT GROUP BY ROLLUP | | 54 | 3402 | 3 (34)| 00:00:01 | | |
| 13 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6E6F_E9BC1839 | 54 | 3402 | 2 (0)| 00:00:01 | | |
| 14 | MULTI-TABLE INSERT | | | | | | | |
| 15 | SORT GROUP BY ROLLUP | | 54 | 3240 | 3 (34)| 00:00:01 | | |
| 16 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6E6F_E9BC1839 | 54 | 3240 | 2 (0)| 00:00:01 | | |
| 17 | DIRECT LOAD INTO | SYS_TEMP_0FD9D6E71_E9BC1839 | | | | | | |
| 18 | DIRECT LOAD INTO | SYS_TEMP_0FD9D6E70_E9BC1839 | | | | | | |
| 19 | LOAD AS SELECT | SYS_TEMP_0FD9D6E70_E9BC1839 | | | | | | |
| 20 | SORT GROUP BY ROLLUP | | 54 | 2322 | 3 (34)| 00:00:01 | | |
| 21 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6E71_E9BC1839 | 54 | 2322 | 2 (0)| 00:00:01 | | |
| 22 | VIEW | | 162 | 19278 | 6 (0)| 00:00:01 | | |
| 23 | VIEW | | 162 | 15066 | 6 (0)| 00:00:01 | | |
| 24 | UNION-ALL | | | | | | | |
| 25 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6E6F_E9BC1839 | 54 | 4536 | 2 (0)| 00:00:01 | | |
| 26 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6E70_E9BC1839 | 54 | 4536 | 2 (0)| 00:00:01 | | |
| 27 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6E71_E9BC1839 | 54 | 3240 | 2 (0)| 00:00:01 | | |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SYS_TBL_$2$"."ETP_ET_UID"="SYS_TBL_$1$"."ET_UID")
Note
-----
- dynamic sampling used for this statement (level=2)

How do I force access by index rowid in Oracle?

I need help forcing Oracle to always use table access by index row id on table "r_rapport" (~60k rows) to subsequently avoid full table scans on "r_attributfeld" (~8m rows) . I have a query resulting in the following plan:
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 22220 | | 63518 (2)| 00:12:43 |
|* 1 | COUNT STOPKEY | | | | | | |
| 2 | VIEW | | 2870 | 616K| | 63518 (2)| 00:12:43 |
|* 3 | SORT ORDER BY STOPKEY | | 2870 | 313K| 696K| 63518 (2)| 00:12:43 |
|* 4 | FILTER | | | | | | |
|* 5 | HASH JOIN SEMI | | 2871 | 314K| | 51920 (2)| 00:10:24 |
|* 6 | HASH JOIN RIGHT SEMI | | 2871 | 299K| | 26084 (2)| 00:05:14 |
| 7 | VIEW | VW_NSO_1 | 214 | 1070 | | 5 (20)| 00:00:01 |
|* 8 | HASH JOIN | | 214 | 5350 | | 5 (20)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | TEST7 | 141 | 1269 | | 2 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | TEST8 | 228 | 3648 | | 2 (0)| 00:00:01 |
|* 11 | HASH JOIN SEMI | | 5848 | 582K| | 26079 (2)| 00:05:13 |
|* 12 | HASH JOIN | | 6547 | 620K| | 243 (2)| 00:00:03 |
|* 13 | INDEX RANGE SCAN | TEST5 | 47 | 470 | | 2 (0)| 00:00:01 |
| 14 | TABLE ACCESS FULL | R_RAPPORT | 60730 | 5159K| | 240 (1)| 00:00:03 |
| 15 | VIEW | VW_SQ_3 | 334K| 1633K| | 25834 (2)| 00:05:11 |
|* 16 | HASH JOIN | | 334K| 14M| 10M| 25834 (2)| 00:05:11 |
| 17 | INDEX FAST FULL SCAN | TEST4 | 476K| 4656K| | 368 (2)| 00:00:05 |
|* 18 | HASH JOIN | | 343K| 11M| 11M| 24214 (2)| 00:04:51 |
|* 19 | TABLE ACCESS FULL | R_ATTRIBUTFELD | 343K| 7722K| | 20483 (2)| 00:04:06 |
| 20 | INDEX FAST FULL SCAN| TEST3 | 1670K| 17M| | 1324 (1)| 00:00:16 |
| 21 | VIEW | VW_SQ_2 | 334K| 1633K| | 25834 (2)| 00:05:11 |
|* 22 | HASH JOIN | | 334K| 14M| 10M| 25834 (2)| 00:05:11 |
| 23 | INDEX FAST FULL SCAN | TEST4 | 476K| 4656K| | 368 (2)| 00:00:05 |
|* 24 | HASH JOIN | | 343K| 11M| 11M| 24214 (2)| 00:04:51 |
|* 25 | TABLE ACCESS FULL | R_ATTRIBUTFELD | 343K| 7722K| | 20483 (2)| 00:04:06 |
| 26 | INDEX FAST FULL SCAN | TEST3 | 1670K| 17M| | 1324 (1)| 00:00:16 |
|* 27 | INDEX RANGE SCAN | TEST6 | 1 | 8 | | 8 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------
By adding a FIRST_ROWS(1) hint, this changes to the much more desired plan:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 220 | 96 (0)| 00:00:02 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 1 | 220 | 96 (0)| 00:00:02 |
|* 3 | FILTER | | | | | |
| 4 | NESTED LOOPS | | 1 | 97 | 16 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | R_RAPPORT | 60730 | 5159K| 6 (0)| 00:00:01 |
| 6 | INDEX FULL SCAN DESCENDING | IDX_R_RAPPORT_3 | 10 | | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | TEST5 | 1 | 10 | 1 (0)| 00:00:01 |
| 8 | NESTED LOOPS | | 1 | 25 | 2 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | TEST7 | 141 | 1269 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | TEST8 | 1 | 16 | 0 (0)| 00:00:01 |
|* 11 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 12 | NESTED LOOPS | | 2 | 88 | 35 (0)| 00:00:01 |
| 13 | NESTED LOOPS | | 10 | 210 | 7 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 15 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 17 | TABLE ACCESS BY INDEX ROWID| R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 18 | NESTED LOOPS | | 2 | 88 | 35 (0)| 00:00:01 |
| 19 | NESTED LOOPS | | 10 | 210 | 7 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 21 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 22 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 23 | INDEX RANGE SCAN | TEST6 | 1 | 8 | 8 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Unfortunately this query is composed at runtime, and should there be three subrequests instead of the two here, it will ignore the FIRST_ROWS hint and again do multiple full table scans on 8 million rows. With the given data distribution access by rowid will always be faster (almost instant) while the plan Oracle prefers takes several seconds.
I tried using ROWID hints on both tables, before discovering those have been deprecated.
Any pointers will be appreciated.
=edit=
USE_NL & new Index
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 22220 | 3994 (1)| 00:00:48 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 102 | 22440 | 3994 (1)| 00:00:48 |
| 3 | NESTED LOOPS SEMI | | 1 | 102 | 16 (7)| 00:00:01 |
| 4 | NESTED LOOPS | | 1 | 97 | 11 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | R_RAPPORT | 58985 | 5011K| 10 (0)| 00:00:01 |
|* 6 | INDEX FULL SCAN DESCENDING | TEST12 | 1 | | 9 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 8 | NESTED LOOPS | | 2 | 88 | 35 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | 10 | 210 | 7 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 11 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 13 | TABLE ACCESS BY INDEX ROWID| R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 14 | NESTED LOOPS | | 2 | 88 | 35 (0)| 00:00:01 |
| 15 | NESTED LOOPS | | 10 | 210 | 7 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 17 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 18 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 19 | INDEX RANGE SCAN | TEST6 | 1 | 8 | 8 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | TEST5 | 1 | 10 | 1 (0)| 00:00:01 |
|* 21 | VIEW | VW_NSO_1 | 105 | 525 | 5 (20)| 00:00:01 |
|* 22 | HASH JOIN | | 214 | 5350 | 5 (20)| 00:00:01 |
|* 23 | INDEX RANGE SCAN | TEST7 | 141 | 1269 | 2 (0)| 00:00:01 |
|* 24 | INDEX RANGE SCAN | TEST8 | 228 | 3648 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
SQL:
select /*+ FIRST_ROWS */ * from (
select *
from r_rapport a
where rb_id in (
select obj_id from obj_recht where obj_typ = 20 and obj_pid = 10065 and maske_id in (
select distinct maske_id
from obj_rechtmaske
where subj_pid = 10065
) )
and rb_id in (
select id from rb_buch where pid = 10065
)
and exists (
select /*+ USE_NL( c d ) */ 1
from r_teilanlage b, r_attribut c, r_attributfeld d
where a.id = b.r_id
and b.id = c.r_teilanlage_id
and c.id = d.r_attribut_id
and d.attributfeld_typ not in ( 20, 25, 40, 78, 79, 90, 92, 123, 124, 125, 126, 127 )
and lower( d.wert ) like lower( '%ä%' )
)
and exists (
select /*+ USE_NL( c d ) */ 1
from r_teilanlage b, r_attribut c, r_attributfeld d
where a.id = b.r_id
and b.id = c.r_teilanlage_id
and c.id = d.r_attribut_id
and d.attributfeld_typ not in ( 20, 25, 40, 78, 79, 90, 92, 123, 124, 125, 126, 127 )
and lower( d.wert ) like lower( '%ö%' )
)
and exists (
select /*+ USE_NL( c d ) */ 1
from r_teilanlage b, r_attribut c, r_attributfeld d
where a.id = b.r_id
and b.id = c.r_teilanlage_id
and c.id = d.r_attribut_id
and d.attributfeld_typ not in ( 20, 25, 40, 78, 79, 90, 92, 123, 124, 125, 126, 127 )
and lower( d.wert ) like lower( '%ä%' )
)
and exists (
select /*+ USE_NL( c d ) */ 1
from r_teilanlage b, r_attribut c, r_attributfeld d
where a.id = b.r_id
and b.id = c.r_teilanlage_id
and c.id = d.r_attribut_id
and d.attributfeld_typ not in ( 20, 25, 40, 78, 79, 90, 92, 123, 124, 125, 126, 127 )
and lower( d.wert ) like lower( '%ö%' )
)
and a.id not in (
select r_id from r_gelesen where ma_id = 144
)
order by a.open_stamp desc
) where rownum <= 101;
and its plan:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 220 | 1195K (1)| 03:59:08 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 1 | 220 | 1195K (1)| 03:59:08 |
|* 3 | FILTER | | | | | |
| 4 | NESTED LOOPS SEMI | | 3213 | 320K| 1018K (1)| 03:23:47 |
| 5 | NESTED LOOPS | | 6547 | 620K| 82249 (1)| 00:16:27 |
| 6 | TABLE ACCESS BY INDEX ROWID | R_RAPPORT | 60730 | 5159K| 21493 (1)| 00:04:18 |
| 7 | INDEX FULL SCAN DESCENDING | IDX_R_RAPPORT_3 | 60730 | | 152 (1)| 00:00:02 |
|* 8 | INDEX RANGE SCAN | TEST5 | 1 | 10 | 1 (0)| 00:00:01 |
|* 9 | VIEW | VW_NSO_1 | 105 | 525 | 143 (0)| 00:00:02 |
| 10 | NESTED LOOPS | | 214 | 5350 | 143 (0)| 00:00:02 |
|* 11 | INDEX RANGE SCAN | TEST7 | 141 | 1269 | 2 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | TEST8 | 2 | 32 | 1 (0)| 00:00:01 |
|* 13 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 14 | NESTED LOOPS | | 6 | 264 | 97 (0)| 00:00:02 |
| 15 | NESTED LOOPS | | 30 | 630 | 13 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 17 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 18 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 19 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 20 | NESTED LOOPS | | 6 | 264 | 97 (0)| 00:00:02 |
| 21 | NESTED LOOPS | | 30 | 630 | 13 (0)| 00:00:01 |
|* 22 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 23 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 24 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 25 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 26 | NESTED LOOPS | | 6 | 264 | 97 (0)| 00:00:02 |
| 27 | NESTED LOOPS | | 30 | 630 | 13 (0)| 00:00:01 |
|* 28 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 29 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 30 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 31 | TABLE ACCESS BY INDEX ROWID| R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 32 | NESTED LOOPS | | 6 | 264 | 97 (0)| 00:00:02 |
| 33 | NESTED LOOPS | | 30 | 630 | 13 (0)| 00:00:01 |
|* 34 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 35 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 36 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 37 | INDEX RANGE SCAN | TEST6 | 1 | 8 | 8 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
A horrible, horrible cost estimate as this query completes instantly.
If you want to avoid table access full on r_attributfeld, you should try a nested loop on this table.
Maybe you'll have to had a leading(r_rapport r_attributfeld) (or ordered hint) if Oracle "don't understand" what you want
Not always what you think is better plan is realy better plan. To return you first rows fast is right way to use nested loops and rowid acces. But if you want return all result set fast it is more efficient to use hash join even if you are joining by rowid("select * from tab where rowid in (...)" or "... join tab on tab.rowid = ...'). So I think Oracle picked right plan for you.

Oracle LEFT JOIN View performance

I have two tables, they aren't large tables.
I have created a View based on this tables
select
tab_a.id as id,
tab_a.name as name
from tableA as tab_a
UNION ALL
select
tab_b.id as id,
tab_b.name as name
from tableB as tab_b
After all, I have a third table, lets call it tableMain with fields:
tableMain.id, tableMain.status, tableMain.viewId
viewId exists to join view
Final select look like
SELECT tableMain.id
FROM tableMain
LEFT OUTER JOIN VIEW ON tableMain.viewId=view.id
and join is very slow on a VIEW.
its fast if I join directly tableA or tableB, but not when using view.
It could be fast if I use view.name in select
SELECT tableMain.id, VIEW.name
FROM tableMain
LEFT OUTER JOIN VIEW ON tableMain.viewId=view.id
Not sure why VIEW JOIN working fast if I use VIEW field in select,
and how make VIEW JOIN fast without it.
Posting plans:
Good Plan (using VIEW.name in SELECT)
SELECT tableMain.id, VIEW.name
FROM tableMain
LEFT OUTER JOIN VIEW ON tableMain.viewId=view.id
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 220K| 440M| 50 (4)| 00:00:01 |
|* 1 | HASH JOIN OUTER | | 220K| 440M| 50 (4)| 00:00:01 |
| 2 | TABLE ACCESS FULL | **tableMain** | 19796 | 1527K| 42 (0)| 00:00:01 |
| 3 | VIEW | ***VIEW*** | 1115 | 2194K| 6 (0)| 00:00:01 |
| 4 | UNION-ALL | | | | | |
| 5 | TABLE ACCESS FULL| **tableA** | 818 | 1609K| 3 (0)| 00:00:01 |
|* 6 | TABLE ACCESS FULL| **tableB** | 297 | 5346 | 3 (0)| 00:00:01 |
Bad Plan (no view.name in select)
SELECT tableMain.id
FROM tableMain
LEFT OUTER JOIN VIEW ON tableMain.viewId=view.id
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
| 0 | SELECT STATEMENT | | 220K| 19M| 51 (6)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10003 | 220K| 19M| 51 (6)| 00:00:01 | Q1,03 | P->S | QC (RAND) |
|* 3 | HASH JOIN RIGHT OUTER | | 220K| 19M| 51 (6)| 00:00:01 | Q1,03 | PCWP | |
| 4 | PX RECEIVE | | 1115 | 14495 | 6 (0)| 00:00:01 | Q1,03 | PCWP | |
| 5 | PX SEND HASH | :TQ10002 | 1115 | 14495 | 6 (0)| 00:00:01 | Q1,02 | P->P | HASH |
| 6 | BUFFER SORT | | 220K| 19M| | | Q1,02 | PCWP | |
| 7 | VIEW | ***VIEW*** | 1115 | 14495 | 6 (0)| 00:00:01 | Q1,02 | PCWP | |
| 8 | UNION-ALL | | | | | | Q1,02 | PCWP | |
| 9 | PX BLOCK ITERATOR | | 818 | 10634 | 3 (0)| 00:00:01 | Q1,02 | PCWC | |
| 10 | INDEX FAST FULL SCAN| ***tableA_PK*** | 818 | 10634 | 3 (0)| 00:00:01 | Q1,02 | PCWP | |
| 11 | BUFFER SORT | | | | | | Q1,02 | PCWC | |
| 12 | PX RECEIVE | | 297 | 2079 | 3 (0)| 00:00:01 | Q1,02 | PCWP | |
| 13 | PX SEND ROUND-ROBIN| :TQ10000 | 297 | 2079 | 3 (0)| 00:00:01 | | S->P | RND-ROBIN |
|* 14 | TABLE ACCESS FULL | **tableB** | 297 | 2079 | 3 (0)| 00:00:01 | | | |
| 15 | BUFFER SORT | | | | | | Q1,03 | PCWC | |
| 16 | PX RECEIVE | | 19796 | 1527K| 42 (0)| 00:00:01 | Q1,03 | PCWP | |
| 17 | PX SEND HASH | :TQ10001 | 19796 | 1527K| 42 (0)| 00:00:01 | | S->P | HASH |
| 18 | TABLE ACCESS FULL | **tableMain** | 19796 | 1527K| 42 (0)| 00:00:01 | | | |
Why so big difference?
Something is forcing parallelism. Does the view have any hints? Is there some type of plan management happening with this query? For example, is there an outline, SQL Plan Management, or profile setup only on the bad query? You may be able to find out by adding
the Note section of the explain plan. If I'm right, there will be something like this in only one of the execution plans:
Note
-----
- SQL plan baseline "SQL_PLAN_01yu884fpund494ecae5c" used FOR this statement
Also it would help to define "very slow". If the good query runs in 0.01 seconds and the bad query runs in 2 seconds, the difference may be all because of the overhead of
parallelism. But if the query was tuned for an environment with much larger data you may want to keep that the bad plan anyway - it may run better in production.

Resources