How do I force access by index rowid in Oracle? - 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.

Related

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

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

How to optimize a complex oracle query using pagination

I need to get data from an oracle DB to paint some sort of matrix in an html table. The query I needed turned out to be very complex and slow, so I decided to implement pagination.
I followed many articles and posts, but the one I liked the most was this one: On rownum and limiting results
But it doesn't seem to work, the execution takes as long time as if there was no rows restriction, sometimes it even takes longer.
Please keep in mind than I'm new with oracle, I'm used to recent versions of MS SQL
Here's a brief example of what my query looks like:
SELECT * FROM (
SELECT /*+ FIRST_ROWS(n) */ a.*, ROWNUM rnum FROM (
WITH T1 AS (
SELECT ... FROM VIEW_1
INNER JOIN ...
WHERE ...
GROUP BY ...
),
T2 AS (
SELECT ... FROM VIEW_2
INNER JOIN ...
WHERE ...
GROUP BY ...
),
T3 AS (
SELECT ... FROM VIEW_3
LEFT JOIN ...
WHERE ...
GROUP BY ...
)
SELECT
T1.LVL,
T1.CRSE,
T2.ID,
T3.GRADE
FROM T1
INNER JOIN T2 ON ...
LEFT JOIN T3 ON ...
ORDER BY T2.ID DESC, T1.LVL, T1.CRSE) a
WHERE ROWNUM <= (PAGE * 50))
WHERE rnum >= ((PAGE-1) * 50);
My actual query is quite larger, and I mostly use views I don't have access to.
I don't know if the /*+ FIRST_ROWS(n) */ works like that... and also don't think I can set a variable there...
I was expecting the execution time to be much lower that without the ROWNUM check, but it just doesn't work, and I've read its because of the GROUP BY usage. Can someone please help me make my pagination faster?
EDIT:
Here's the EXPLAIN PLAN from my query, I hope it helps:
Plan hash value: 3394899150
-----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3950 | 648K| | 17918 (1)| 00:03:36 |
|* 1 | VIEW | | 3950 | 648K| | 17918 (1)| 00:03:36 |
|* 2 | COUNT STOPKEY | | | | | | |
| 3 | VIEW | | 8424 | 1275K| | 17918 (1)| 00:03:36 |
| 4 | TEMP TABLE TRANSFORMATION | | | | | | |
| 5 | LOAD AS SELECT | SYS_TEMP_0FD9D6FD2_17D15EA9 | | | | | |
| 6 | HASH UNIQUE | | 36 | 2052 | | 250 (1)| 00:00:03 |
| 7 | VIEW | PS_UAG_ISBI_MAT_VW | 36 | 2052 | | 249 (1)| 00:00:03 |
|* 8 | HASH JOIN | | 36 | 3744 | | 249 (1)| 00:00:03 |
| 9 | NESTED LOOPS | | 34 | 2312 | | 14 (0)| 00:00:01 |
| 10 | NESTED LOOPS | | 44 | 2312 | | 14 (0)| 00:00:01 |
| 11 | NESTED LOOPS | | 1 | 46 | | 5 (0)| 00:00:01 |
| 12 | TABLE ACCESS BY INDEX ROWID | PS_ACAD_PROG_TBL | 1 | 29 | | 4 (0)| 00:00:01 |
|* 13 | INDEX SKIP SCAN | PS1ACAD_PROG_TBL | 1 | | | 3 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | PS1ACAD_ORG_TBL | 1 | 17 | | 1 (0)| 00:00:01 |
|* 15 | INDEX RANGE SCAN | PS2CRSE_OFFER | 44 | | | 1 (0)| 00:00:01 |
|* 16 | TABLE ACCESS BY INDEX ROWID | PS_CRSE_OFFER | 33 | 726 | | 9 (0)| 00:00:01 |
| 17 | VIEW | | 12227 | 429K| | 235 (1)| 00:00:03 |
|* 18 | HASH JOIN RIGHT OUTER | | 12227 | 573K| | 235 (1)| 00:00:03 |
|* 19 | INDEX FAST FULL SCAN | PS_CRSE_ATTRIBUTES | 7690 | 135K| | 98 (0)| 00:00:02 |
| 20 | TABLE ACCESS FULL | PS_CRSE_CATALOG | 12227 | 358K| | 136 (0)| 00:00:02 |
| 21 | LOAD AS SELECT | SYS_TEMP_0FD9D6FD3_17D15EA9 | | | | | |
| 22 | VIEW | | 682 | 36146 | | 1091 (1)| 00:00:14 |
|* 23 | HASH JOIN | | 682 | 41602 | | 1091 (1)| 00:00:14 |
|* 24 | TABLE ACCESS FULL | TYM_TRAYECTORIA | 682 | 17050 | | 513 (1)| 00:00:07 |
| 25 | INDEX FAST FULL SCAN | PS0PERSONAL_DATA | 255K| 8985K| | 577 (1)| 00:00:07 |
| 26 | LOAD AS SELECT | SYS_TEMP_0FD9D6FD4_17D15EA9 | | | | | |
| 27 | HASH GROUP BY | | 107 | 1605 | | 16164 (1)| 00:03:14 |
| 28 | VIEW | | 107 | 1605 | | 16163 (1)| 00:03:14 |
|* 29 | HASH JOIN | | 107 | 2461 | | 16163 (1)| 00:03:14 |
| 30 | VIEW | | 682 | 5456 | | 3 (0)| 00:00:01 |
| 31 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6FD3_17D15EA9 | 682 | 36146 | | 3 (0)| 00:00:01 |
| 32 | VIEW | PS_UAG_ISBI_CAL_VW | 6411 | 96165 | | 16160 (1)| 00:03:14 |
| 33 | SORT UNIQUE | | 6411 | 7004K| 1960K| 16160 (1)| 00:03:14 |
| 34 | UNION-ALL | | | | | | |
|* 35 | HASH JOIN | | 6342 | 1839K| | 15289 (1)| 00:03:04 |
|* 36 | INDEX FAST FULL SCAN | PS_CRSE_ATTRIBUTES | 7690 | 135K| | 98 (0)| 00:00:02 |
|* 37 | HASH JOIN | | 4943 | 1346K| | 15191 (1)| 00:03:03 |
|* 38 | HASH JOIN | | 4943 | 1168K| | 10790 (1)| 00:02:10 |
| 39 | INDEX FAST FULL SCAN | PS1TERM_TBL | 1256 | 31400 | | 4 (0)| 00:00:01 |
|* 40 | HASH JOIN | | 4943 | 1047K| | 10786 (1)| 00:02:10 |
| 41 | INDEX FAST FULL SCAN | PS0CRSE_CATALOG | 12227 | 358K| | 31 (0)| 00:00:01 |
|* 42 | HASH JOIN | | 4985 | 910K| | 10755 (1)| 00:02:10 |
| 43 | TABLE ACCESS FULL | PS_ACAD_ORG_TBL | 549 | 23058 | | 7 (0)| 00:00:01 |
|* 44 | HASH JOIN | | 5297 | 750K| 2856K| 10748 (1)| 00:02:09 |
| 45 | TABLE ACCESS FULL | PS_CLASS_TBL | 52112 | 2239K| | 650 (1)| 00:00:08 |
|* 46 | HASH JOIN | | 100K| 9893K| | 9422 (1)| 00:01:54 |
| 47 | TABLE ACCESS FULL | PS_ACAD_PROG_TBL | 313 | 18467 | | 5 (0)| 00:00:01 |
|* 48 | TABLE ACCESS FULL | PS_STDNT_ENRL | 986K| 39M| | 9414 (1)| 00:01:53 |
| 49 | TABLE ACCESS FULL | PS_PERSONAL_DATA | 255K| 9235K| | 4400 (1)| 00:00:53 |
| 50 | NESTED LOOPS | | 69 | 19596 | | 462 (1)| 00:00:06 |
| 51 | NESTED LOOPS | | 69 | 19596 | | 462 (1)| 00:00:06 |
|* 52 | HASH JOIN | | 69 | 17043 | | 324 (1)| 00:00:04 |
|* 53 | HASH JOIN | | 69 | 15318 | | 320 (1)| 00:00:04 |
|* 54 | HASH JOIN | | 105 | 21420 | | 222 (1)| 00:00:03 |
|* 55 | HASH JOIN | | 101 | 17574 | | 191 (1)| 00:00:03 |
|* 56 | HASH JOIN | | 101 | 14443 | | 88 (0)| 00:00:02 |
|* 57 | HASH JOIN | | 314 | 31714 | | 12 (0)| 00:00:01 |
| 58 | TABLE ACCESS FULL | PS_ACAD_PROG_TBL | 313 | 18467 | | 5 (0)| 00:00:01 |
| 59 | TABLE ACCESS FULL | PS_ACAD_ORG_TBL | 549 | 23058 | | 7 (0)| 00:00:01 |
| 60 | VIEW | | 7540 | 309K| | 76 (0)| 00:00:01 |
|* 61 | HASH JOIN | | 7540 | 493K| | 76 (0)| 00:00:01 |
| 62 | TABLE ACCESS FULL | PS_TRNS_CRSE_SCH | 597 | 16119 | | 6 (0)| 00:00:01 |
| 63 | TABLE ACCESS FULL | PS_TRNS_CRSE_DTL | 7540 | 294K| | 70 (0)| 00:00:01 |
| 64 | TABLE ACCESS FULL | PS_CRSE_OFFER | 12227 | 370K| | 102 (0)| 00:00:02 |
| 65 | INDEX FAST FULL SCAN | PS0CRSE_CATALOG | 12227 | 358K| | 31 (0)| 00:00:01 |
|* 66 | INDEX FAST FULL SCAN | PS_CRSE_ATTRIBUTES | 7690 | 135K| | 98 (0)| 00:00:02 |
| 67 | INDEX FAST FULL SCAN | PS1TERM_TBL | 1256 | 31400 | | 4 (0)| 00:00:01 |
|* 68 | INDEX UNIQUE SCAN | PS_PERSONAL_DATA | 1 | | | 1 (0)| 00:00:01 |
| 69 | TABLE ACCESS BY INDEX ROWID | PS_PERSONAL_DATA | 1 | 37 | | 2 (0)| 00:00:01 |
|* 70 | SORT ORDER BY STOPKEY | | 8424 | 1628K| 1736K| 413 (1)| 00:00:05 |
|* 71 | HASH JOIN RIGHT OUTER | | 8424 | 1628K| | 46 (5)| 00:00:01 |
| 72 | VIEW | | 108 | 2700 | | 2 (0)| 00:00:01 |
| 73 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6FD4_17D15EA9 | 108 | 1620 | | 2 (0)| 00:00:01 |
|* 74 | HASH JOIN RIGHT OUTER | | 78 | 13494 | | 44 (5)| 00:00:01 |
| 75 | VIEW | | 26 | 390 | | 24 (5)| 00:00:01 |
| 76 | HASH GROUP BY | | 26 | 702 | | 24 (5)| 00:00:01 |
| 77 | VIEW | | 47 | 1269 | | 24 (5)| 00:00:01 |
| 78 | HASH GROUP BY | | 47 | 2256 | | 24 (5)| 00:00:01 |
|* 79 | HASH JOIN OUTER | | 47 | 2256 | | 23 (0)| 00:00:01 |
|* 80 | HASH JOIN OUTER | | 47 | 1081 | | 21 (0)| 00:00:01 |
| 81 | VIEW | | 36 | 360 | | 2 (0)| 00:00:01 |
| 82 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6FD2_17D15EA9 | 36 | 2052 | | 2 (0)| 00:00:01 |
| 83 | TABLE ACCESS FULL | PS_RQ_GRP_DETL_TBL | 2702 | 35126 | | 19 (0)| 00:00:01 |
| 84 | VIEW | | 108 | 2700 | | 2 (0)| 00:00:01 |
| 85 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6FD4_17D15EA9 | 108 | 1620 | | 2 (0)| 00:00:01 |
|* 86 | HASH JOIN RIGHT OUTER | | 78 | 12324 | | 20 (5)| 00:00:01 |
| 87 | TABLE ACCESS FULL | PS_UAG_PRECARG_SUBJECT | 12 | 168 | | 3 (0)| 00:00:01 |
|* 88 | HASH JOIN RIGHT OUTER | | 78 | 11232 | | 17 (6)| 00:00:01 |
| 89 | VIEW | | 1 | 20 | | 12 (9)| 00:00:01 |
| 90 | HASH GROUP BY | | 1 | 30 | | 12 (9)| 00:00:01 |
| 91 | VIEW | PS_UAG_OFERCRSE_VW | 1 | 30 | | 12 (9)| 00:00:01 |
| 92 | HASH UNIQUE | | 1 | 213 | | 12 (9)| 00:00:01 |
| 93 | NESTED LOOPS OUTER | | 1 | 213 | | 11 (0)| 00:00:01 |
| 94 | NESTED LOOPS OUTER | | 1 | 177 | | 9 (0)| 00:00:01 |
| 95 | NESTED LOOPS OUTER | | 1 | 139 | | 6 (0)| 00:00:01 |
|* 96 | TABLE ACCESS BY INDEX ROWID| PS_CLASS_TBL | 1 | 69 | | 4 (0)| 00:00:01 |
|* 97 | INDEX RANGE SCAN | PSDCLASS_TBL | 1 | | | 3 (0)| 00:00:01 |
| 98 | TABLE ACCESS BY INDEX ROWID| PS_CLASS_MTG_PAT | 1 | 70 | | 2 (0)| 00:00:01 |
|* 99 | INDEX RANGE SCAN | PS_CLASS_MTG_PAT | 1 | | | 1 (0)| 00:00:01 |
| 100 | TABLE ACCESS BY INDEX ROWID | PS_CLASS_INSTR | 1 | 38 | | 3 (0)| 00:00:01 |
|*101 | INDEX RANGE SCAN | PS_CLASS_INSTR | 1 | | | 2 (0)| 00:00:01 |
| 102 | TABLE ACCESS BY INDEX ROWID | PS_PERSONAL_DATA | 1 | 36 | | 2 (0)| 00:00:01 |
|*103 | INDEX UNIQUE SCAN | PS_PERSONAL_DATA | 1 | | | 1 (0)| 00:00:01 |
| 104 | VIEW | | 78 | 9672 | | 5 (0)| 00:00:01 |
|*105 | HASH JOIN | | 78 | 10140 | | 5 (0)| 00:00:01 |
| 106 | VIEW | | 36 | 2988 | | 2 (0)| 00:00:01 |
| 107 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6FD2_17D15EA9 | 36 | 2052 | | 2 (0)| 00:00:01 |
| 108 | VIEW | | 682 | 32054 | | 3 (0)| 00:00:01 |
| 109 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6FD3_17D15EA9 | 682 | 36146 | | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RNUM">=0)
2 - filter(ROWNUM<=3950)
8 - access("D"."CRSE_ID"="C"."CRSE_ID")
13 - access("A"."ACAD_PROG"='LMC09')
filter("A"."ACAD_PROG"='LMC09')
14 - access("B"."INSTITUTION"="A"."INSTITUTION" AND "B"."ACAD_ORG"="A"."ACAD_ORG")
15 - access("C"."SUBJECT"="A"."ACAD_PLAN")
16 - filter("C"."INSTITUTION"="A"."INSTITUTION")
18 - access("E"."CRSE_ID"(+)="D"."CRSE_ID")
19 - filter("E"."CRSE_ATTR"(+)='0003')
23 - access("PERS"."EMPLID"="TRA"."EMPLID")
24 - filter("TRA"."STRM"='1835' AND "TRA"."ACAD_PLAN"='LMC09')
29 - access("A2"."EMPLID"="CAL"."EMPLID")
35 - access("F"."CRSE_ID"="E"."CRSE_ID")
36 - filter("F"."CRSE_ATTR"='0003')
37 - access("B"."EMPLID"="A"."EMPLID")
38 - access("H"."INSTITUTION"="A"."INSTITUTION" AND "H"."ACAD_CAREER"="A"."ACAD_CAREER" AND "H"."STRM"="A"."STRM")
40 - access("E"."CRSE_ID"="C"."CRSE_ID")
42 - access("G"."INSTITUTION"="A"."INSTITUTION" AND "G"."ACAD_ORG"="D"."ACAD_ORG")
44 - access("C"."INSTITUTION"="A"."INSTITUTION" AND "C"."ACAD_CAREER"="A"."ACAD_CAREER" AND "C"."STRM"="A"."STRM" AND
"C"."CLASS_NBR"="A"."CLASS_NBR" AND "C"."SESSION_CODE"="A"."SESSION_CODE")
46 - access("D"."INSTITUTION"="A"."INSTITUTION" AND "D"."ACAD_CAREER"="A"."ACAD_CAREER" AND
"D"."ACAD_PROG"="A"."ACAD_PROG")
48 - filter("A"."STDNT_ENRL_STATUS"='E')
52 - access("H"."INSTITUTION"="A"."INSTITUTION" AND "H"."ACAD_CAREER"="A"."ACAD_CAREER" AND
"H"."STRM"="A"."ARTICULATION_TERM")
53 - access("F"."CRSE_ID"="E"."CRSE_ID")
54 - access("E"."CRSE_ID"="C"."CRSE_ID")
55 - access("C"."INSTITUTION"="A"."INSTITUTION" AND "C"."ACAD_CAREER"="A"."ACAD_CAREER" AND "C"."CRSE_ID"="A"."CRSE_ID")
56 - access("D"."INSTITUTION"="A"."INSTITUTION" AND "D"."ACAD_CAREER"="A"."ACAD_CAREER" AND
"D"."ACAD_PROG"="A"."ACAD_PROG" AND "G"."INSTITUTION"="A"."INSTITUTION")
57 - access("G"."ACAD_ORG"="D"."ACAD_ORG")
61 - access("B"."EMPLID"="A"."EMPLID" AND "B"."ACAD_CAREER"="A"."ACAD_CAREER" AND "B"."INSTITUTION"="A"."INSTITUTION"
AND "B"."MODEL_NBR"="A"."MODEL_NBR")
66 - filter("F"."CRSE_ATTR"='0003')
68 - access("B"."EMPLID"="A"."EMPLID")
70 - filter(ROWNUM<=3950)
71 - access("C3"."CRSE_ID"(+)="from$_subquery$_019"."CRSE_ID" AND "C3"."EMPLID"(+)="from$_subquery$_019"."EMPLID")
74 - access("R3"."EMPLID"(+)="from$_subquery$_019"."EMPLID" AND
"R3"."RQRMNT_GROUP"(+)="from$_subquery$_019"."RQRMNT_GROUP")
filter("from$_subquery$_019"."RQRMNT_GROUP"<>CASE WHEN ("R3"."RQRMNT_GROUP"(+) IS NOT NULL) THEN ' ' ELSE ' ' END )
79 - access("REQ"."CRSE_ID"="C2"."CRSE_ID"(+))
80 - access("REQ"."RQRMNT_GROUP"(+)="M2"."RQRMNT_GROUP")
filter("M2"."RQRMNT_GROUP"<>CASE WHEN ("REQ"."RQRMNT_GROUP"(+) IS NOT NULL) THEN ' ' ELSE ' ' END )
86 - access("DTL"."CRSE_ID"(+)="M3"."CRSE_ID" AND "A3"."IDTRAYECTORIA"=TO_NUMBER("DTL"."ID_TRAYECTORIA"(+)))
88 - access("H3"."CRSE_ID"(+)="from$_subquery$_019"."CRSE_ID")
96 - filter("A"."SESSION_CODE"='ORD' AND "A"."CLASS_STAT"='A')
97 - access("A"."SUBJECT"='LMC09' AND "A"."STRM"='1853')
99 - access("B"."CRSE_ID"(+)="A"."CRSE_ID" AND "B"."CRSE_OFFER_NBR"(+)="A"."CRSE_OFFER_NBR" AND "B"."STRM"(+)='1853' AND
"B"."SESSION_CODE"(+)='ORD' AND "B"."CLASS_SECTION"(+)="A"."CLASS_SECTION")
101 - access("C"."CRSE_ID"(+)="B"."CRSE_ID" AND "C"."CRSE_OFFER_NBR"(+)="B"."CRSE_OFFER_NBR" AND "C"."STRM"(+)="B"."STRM"
AND "C"."SESSION_CODE"(+)="B"."SESSION_CODE" AND "C"."CLASS_SECTION"(+)="B"."CLASS_SECTION" AND
"C"."CLASS_MTG_NBR"(+)="B"."CLASS_MTG_NBR")
103 - access("D"."EMPLID"(+)="C"."EMPLID")
105 - access("M3"."ACAD_PLAN"="A3"."ACAD_PLAN")
EDIT 2, SOLUTION:
I Managed to find the indexes already configured for the table 'PS_STDNT_ENRL' using the following query:
SELECT
index_owner, index_name, table_name, column_name, column_position
FROM DBA_IND_COLUMNS
WHERE table_name = 'PS_STDNT_ENRL'
ORDER BY
index_owner,
table_name,
index_name,
column_position;
And found the columns needed on my WHERE clause so that the index works.
I modified my query and now its very fast.
ROWNUM only limits the number of rows presented AFTER the query runs and returns ALL rows. So it is still doing all of the work.
If t1.id is numeric, you can use MOD() to reduce the amount of work up front and easily chunk-up your results into as many sections as you desire. By way of example, MOD() of 5 against t1.id would allow you to break the results up into 5 sections corresponding to MOD() results of 0,1,2,3,4.
SELECT MOD(/*t1.id*/1000,5) FROM dual;
In this manner you reduce the number of rows considered in your driving table (t1) so there is less data to be managed after the other tables are joined in.
It would look something like this:
AND MOD(t1.id,5) =
00 -- Partition 1
-- 01 -- Partition 2
-- 02 -- Partition 3
-- 03 -- Partition 4
-- 04 -- Partition 5

Oracle Explain Plan Optimization

I have a complex Oracle UNION query working fine. The query execution take time since it has to traverse through too many records. I need to analyze this query and optimize as much as possible.
SELECT DISTINCT APP.APPLICATION_ID, APE.ENTITY_ID ENTITY_ID, APE.PARENT_ENTITY_ID, RP.ROLE_ID, RP.ACTION_ID, COALESCE(APE_MLD.ENTITY_NAME, APE.ENTITY_NAME)
ENTITY_NAME, RP.CURRENT_RECORD_STATUS_ID, COALESCE(ACT_MLD.ACTION_NAME, ACT.ACTION_NAME) ACTION_NAME, APE.ENTITY_PATH, APE.ADMIN_TYPE_ID, APE.IS_ADMIN_PAGE,
'RO.CR_NO', APE.ENTITY_CODE
FROM AUTH_APPLICATION_ENTITIES APE
INNER JOIN AUTH_APPLICATIONS APP ON APE.APPLICATION_ID = APP.APPLICATION_ID
LEFT JOIN AUTH_APPLICATION_ENTITIES_MLD APE_MLD ON APE.ENTITY_ID = APE_MLD.ENTITY_ID AND APE_MLD.LANGUAGE_ID = 1
LEFT JOIN AUTH_APPLICATION_ENTITIES PARENT_APE ON APE.PARENT_ENTITY_ID = PARENT_APE.ENTITY_ID
LEFT JOIN AUTH_APPLICATION_ENTITIES_MLD PARENT_APE_MLD ON PARENT_APE.ENTITY_ID = PARENT_APE_MLD.ENTITY_ID AND PARENT_APE_MLD.LANGUAGE_ID = 1
INNER JOIN AUTH_ROLES_PRIVILEGES RP ON APE.ENTITY_ID = RP.ENTITY_ID AND RP.CURRENT_RECORD_STATUS_ID NOT IN (2, 3, 6, 8, 9, 10)
INNER JOIN AUTH_ACTIONS ACT ON RP.ACTION_ID = ACT.ACTION_ID
LEFT JOIN AUTH_ACTIONS_MLD ACT_MLD ON ACT.ACTION_ID = ACT_MLD.ACTION_ID AND ACT_MLD.LANGUAGE_ID = 1
INNER JOIN AUTH_USERS_ROLES RO ON RP.ROLE_ID = RO.ROLE_ID AND RO.CURRENT_RECORD_STATUS_ID NOT IN (2, 3, 6, 8, 9, 10)
WHERE APE.CURRENT_RECORD_STATUS_ID ! = 2
AND RP.CURRENT_RECORD_STATUS_ID ! = 2
AND (APE.APPLICATION_ID = 715 OR 715 = -99)
AND RO.USER_ID = 1255162
AND (RO.ROLE_ID = -99 OR -99 = -99)
AND (APE.IS_ADMIN_PAGE = 0 OR USER_HAS_ADMIN_PRIVILEGES(APE.APPLICATION_ID, APE.ADMIN_TYPE_ID, 1255162) = 1)
UNION
SELECT DISTINCT APP.APPLICATION_ID, APE.ENTITY_ID ENTITY_ID, APE.PARENT_ENTITY_ID, RP.ROLE_ID, RP.ACTION_ID, COALESCE(APE_MLD.ENTITY_NAME, APE.ENTITY_NAME)
ENTITY_NAME, RP.CURRENT_RECORD_STATUS_ID, COALESCE(ACT_MLD.ACTION_NAME, ACT.ACTION_NAME) ACTION_NAME, APE.ENTITY_PATH, APE.ADMIN_TYPE_ID, APE.IS_ADMIN_PAGE,
'CR_NO' CR_NO, APE.ENTITY_CODE
FROM AUTH_APPLICATION_ENTITIES APE
INNER JOIN AUTH_APPLICATIONS APP ON APE.APPLICATION_ID = APP.APPLICATION_ID
LEFT JOIN AUTH_APPLICATION_ENTITIES_MLD APE_MLD ON APE.ENTITY_ID = APE_MLD.ENTITY_ID AND APE_MLD.LANGUAGE_ID = 1
LEFT JOIN AUTH_APPLICATION_ENTITIES PARENT_APE ON APE.PARENT_ENTITY_ID = PARENT_APE.ENTITY_ID
LEFT JOIN AUTH_APPLICATION_ENTITIES_MLD PARENT_APE_MLD ON PARENT_APE.ENTITY_ID = PARENT_APE_MLD.ENTITY_ID AND PARENT_APE_MLD.LANGUAGE_ID = 1
INNER JOIN AUTH_ROLES_PRIVILEGES RP ON APE.ENTITY_ID = RP.ENTITY_ID AND RP.CURRENT_RECORD_STATUS_ID NOT IN (2, 3, 6, 8, 9, 10)
INNER JOIN AUTH_ACTIONS ACT ON RP.ACTION_ID = ACT.ACTION_ID
LEFT JOIN AUTH_ACTIONS_MLD ACT_MLD ON ACT.ACTION_ID = ACT_MLD.ACTION_ID AND ACT_MLD.LANGUAGE_ID = 1
INNER JOIN AUTH_ROLE_TYPE_ROLES RTO ON RP.ROLE_ID = RTO.ROLE_ID AND RTO.CURRENT_RECORD_STATUS_ID NOT IN (2, 3, 6, 8, 9, 10)
WHERE APE.CURRENT_RECORD_STATUS_ID ! = 2
AND RP.CURRENT_RECORD_STATUS_ID ! = 2
AND (APE.APPLICATION_ID = 715 OR 715 = -99)
AND RTO.ROLE_TYPE_ID IN (SELECT ROLE_TYPE_ID FROM AUTH_USER_TYPES WHERE USER_ID = 1255162)
AND (RTO.ROLE_ID = -99 OR -99 = -99)
AND (APE.IS_ADMIN_PAGE = 0 OR USER_HAS_ADMIN_PRIVILEGES(APE.APPLICATION_ID, APE.ADMIN_TYPE_ID, 1255162) = 1);
I have generated the explain plan and it provide this result:
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 40 | 11232 | 1485 (63)| 00:00:18 |
| 1 | SORT UNIQUE | | 40 | 11232 | 1485 (63)| 00:00:18 |
| 2 | UNION-ALL | | | | | |
|* 3 | HASH JOIN OUTER | | 26 | 7228 | 631 (13)| 00:00:08 |
| 4 | NESTED LOOPS OUTER | | 22 | 5016 | 625 (13)| 00:00:08 |
| 5 | NESTED LOOPS OUTER | | 22 | 4862 | 625 (13)| 00:00:08 |
| 6 | NESTED LOOPS | | 22 | 4774 | 625 (13)| 00:00:08 |
|* 7 | HASH JOIN OUTER | | 22 | 4686 | 625 (13)| 00:00:08 |
|* 8 | HASH JOIN | | 22 | 4246 | 622 (13)| 00:00:08 |
|* 9 | HASH JOIN | | 22 | 3872 | 620 (13)| 00:00:08 |
|* 10 | TABLE ACCESS BY INDEX ROWID| AUTH_APPLICATION_ENTITIES | 40 | 5920 | 7 (0)| 00:00:01 |
|* 11 | INDEX RANGE SCAN | AUTH_AE_IDX_APP | 49 | | 1 (0)| 00:00:01 |
| 12 | NESTED LOOPS | | 597 | 16716 | 612 (13)| 00:00:08 |
|* 13 | TABLE ACCESS FULL | AUTH_USERS_ROLES | 5 | 65 | 607 (13)| 00:00:08 |
|* 14 | INDEX RANGE SCAN | AUTH_ROLES_PRIVILEGES_UK1 | 131 | 1965 | 1 (0)| 00:00:01 |
| 15 | TABLE ACCESS FULL | AUTH_ACTIONS | 11 | 187 | 2 (0)| 00:00:01 |
|* 16 | TABLE ACCESS FULL | AUTH_ACTIONS_MLD | 9 | 180 | 2 (0)| 00:00:01 |
|* 17 | INDEX UNIQUE SCAN | PK_SYS_MODULES | 1 | 4 | 0 (0)| 00:00:01 |
|* 18 | INDEX UNIQUE SCAN | PK_SYS_ENTITIES | 1 | 4 | 0 (0)| 00:00:01 |
|* 19 | INDEX UNIQUE SCAN | AUTH_APPLICATION_ENTITIES_UK1 | 1 | 7 | 0 (0)| 00:00:01 |
|* 20 | TABLE ACCESS FULL | AUTH_APPLICATION_ENTITIES_MLD | 1262 | 63100 | 5 (0)| 00:00:01 |
|* 21 | HASH JOIN OUTER | | 14 | 4004 | 852 (17)| 00:00:11 |
| 22 | NESTED LOOPS OUTER | | 12 | 2832 | 847 (17)| 00:00:11 |
| 23 | NESTED LOOPS OUTER | | 12 | 2748 | 847 (17)| 00:00:11 |
| 24 | NESTED LOOPS | | 12 | 2700 | 847 (17)| 00:00:11 |
|* 25 | HASH JOIN OUTER | | 12 | 2652 | 847 (17)| 00:00:11 |
|* 26 | HASH JOIN | | 12 | 2412 | 844 (17)| 00:00:11 |
|* 27 | HASH JOIN | | 12 | 2208 | 842 (17)| 00:00:11 |
|* 28 | TABLE ACCESS BY INDEX ROWID| AUTH_APPLICATION_ENTITIES | 40 | 5920 | 7 (0)| 00:00:01 |
|* 29 | INDEX RANGE SCAN | AUTH_AE_IDX_APP | 49 | | 1 (0)| 00:00:01 |
| 30 | NESTED LOOPS | | 308 | 11088 | 834 (17)| 00:00:11 |
|* 31 | HASH JOIN | | 3 | 63 | 831 (17)| 00:00:10 |
|* 32 | TABLE ACCESS FULL | AUTH_USER_TYPES | 4 | 40 | 829 (17)| 00:00:10 |
|* 33 | TABLE ACCESS FULL | AUTH_ROLE_TYPE_ROLES | 9 | 99 | 2 (0)| 00:00:01 |
|* 34 | INDEX RANGE SCAN | AUTH_ROLES_PRIVILEGES_UK1 | 89 | 1335 | 1 (0)| 00:00:01 |
| 35 | TABLE ACCESS FULL | AUTH_ACTIONS | 11 | 187 | 2 (0)| 00:00:01 |
|* 36 | TABLE ACCESS FULL | AUTH_ACTIONS_MLD | 9 | 180 | 2 (0)| 00:00:01 |
|* 37 | INDEX UNIQUE SCAN | PK_SYS_MODULES | 1 | 4 | 0 (0)| 00:00:01 |
|* 38 | INDEX UNIQUE SCAN | PK_SYS_ENTITIES | 1 | 4 | 0 (0)| 00:00:01 |
|* 39 | INDEX UNIQUE SCAN | AUTH_APPLICATION_ENTITIES_UK1 | 1 | 7 | 0 (0)| 00:00:01 |
|* 40 | TABLE ACCESS FULL | AUTH_APPLICATION_ENTITIES_MLD | 1262 | 63100 | 5 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------
I need to optimize the above query by reading the explain plan result. I just need to know how I can find JOIN orders and slow queries etc. Can anyoe please help me on this?
With that is difficult to help, we don't know where your sql lost time.
run the query with the hint /*+ GATHER_PLAN_STATISTICS */ or alter your session with
alter session set statistics_level='ALL', and then put the result of the plan here with:
SELECT *
FROM table(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST'));
Or if you want is easy to read, use DBMS_SQL_MONITOR to check query

How to force optimizer to reuse sql cursor

We have a problem with the oracle optimizer at oracle 12c. It takes several executions of a sql statement until the sql is marked as IS_REOPTIMIZABLE=N.
Following output of the same statement and nearly the same data at oracle11g/oracle12c.
-- output of v$sql (oracle 12c)
SQL_ID CHILD_NUMBER IS_REOPTIMIZABLE IS_BIND_SENSITIVE ELAPSED_TIME IS_BIND_AWARE IS_SHAREABLE IS_OBSOLETE FETCHES EXECUTIONS OPTIMIZER_COST SQL_PLAN_BASELINE
0f83zdknhqsmj 1 Y N 12575247 N N N 1 1 35 SQL_PLAN_3b0ugvyu8w97a4132b007
0f83zdknhqsmj 2 Y N 78337268 N N N 1 1 35 SQL_PLAN_3b0ugvyu8w97a4132b007
0f83zdknhqsmj 3 Y N 6079189 N N N 1 1 35 SQL_PLAN_3b0ugvyu8w97a4132b007
0f83zdknhqsmj 4 Y N 6162748 N N N 1 1 35 SQL_PLAN_3b0ugvyu8w97a4132b007
0f83zdknhqsmj 5 Y N 6647007 N N N 1 1 35 SQL_PLAN_3b0ugvyu8w97a4132b007
0f83zdknhqsmj 6 N N 6939813 N Y N 3 3 35 SQL_PLAN_3b0ugvyu8w97a4132b007
-- output of v$sql (oracle 11g)
SQL_ID CHILD_NUMBER IS_BIND_SENSITIVE ELAPSED_TIME IS_BIND_AWARE IS_SHAREABLE IS_OBSOLETE FETCHES EXECUTIONS OPTIMIZER_COST SQL_PLAN_BASELINE
0f83zdknhqsmj 0 N 2630792 N Y N 2 2 35 SQL_PLAN_3b0ugvyu8w97a4132b007
As you can see
the elapsed time is quite bad on oracle 12c. Finally the execution plan of the baseline is always used, this plan is good enough. If the cursor is reused (execution>=7), the elapsed time is about 0,25 seconds
on oracle 11g the cursor is reused immediatly , on oracle 12c the optimizer needs 6 tries until it reuses the cursor and the elapsed time is acceptable. After a short while the optimizer retries to optimize the sql.
So the question is:
How can we force the optimizer to reuse the sql cursor and reduce its effort for reoptimization?
Here are some maybe necessary informations, if you need more let me know.
Thanks in advance!
-- optimization hints
select v.CHILD_NUMBER, v.HINT_ID, v.HINT_TEXT from V$SQL_REOPTIMIZATION_HINTS v where v.SQL_ID = '0f83zdknhqsmj';
CHILD_NUMBER HINT_ID HINT_TEXT
5 1 OPT_ESTIMATE (#"SEL$8" TABLE "HEFTFOLGE"#"SEL$8" MIN=132.000000 )
5 2 OPT_ESTIMATE (#"SEL$8" INDEX_FILTER "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=132.000000 )
5 3 OPT_ESTIMATE (#"SEL$8" INDEX_SCAN "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=132.000000 )
4 1 OPT_ESTIMATE (#"SEL$8" TABLE "HEFTFOLGE"#"SEL$8" MIN=578.000000 )
4 2 OPT_ESTIMATE (#"SEL$8" INDEX_FILTER "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=578.000000 )
4 3 OPT_ESTIMATE (#"SEL$8" INDEX_SCAN "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=578.000000 )
3 1 OPT_ESTIMATE (#"SEL$8" TABLE "HEFTFOLGE"#"SEL$8" MIN=75.000000 )
3 2 OPT_ESTIMATE (#"SEL$8" INDEX_FILTER "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=76.000000 )
3 3 OPT_ESTIMATE (#"SEL$8" INDEX_SCAN "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=76.000000 )
2 1 OPT_ESTIMATE (#"SEL$8" TABLE "HEFTFOLGE"#"SEL$8" MIN=730.000000 )
2 2 OPT_ESTIMATE (#"SEL$8" INDEX_FILTER "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=730.000000 )
2 3 OPT_ESTIMATE (#"SEL$8" INDEX_SCAN "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=730.000000 )
1 1 OPT_ESTIMATE (#"SEL$8" TABLE "HEFTFOLGE"#"SEL$8" MIN=1644.000000 )
1 2 OPT_ESTIMATE (#"SEL$8" INDEX_FILTER "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=1644.000000 )
1 3 OPT_ESTIMATE (#"SEL$8" INDEX_SCAN "HEFTFOLGE"#"SEL$8" "PS_CS_HEFTFOLGE_TB" MIN=1644.000000 )
-- Optimizer settings
NAME VALUE
plsql_optimize_level 2
optimizer_features_enable 12.1.0.2
optimizer_mode ALL_ROWS
_optimizer_max_permutations 50
optimizer_index_cost_adj 20
optimizer_index_caching 0
optimizer_dynamic_sampling 4
optimizer_secure_view_merging TRUE
optimizer_use_pending_statistics FALSE
optimizer_capture_sql_plan_baselines FALSE
optimizer_use_sql_plan_baselines TRUE
optimizer_use_invisible_indexes FALSE
optimizer_adaptive_reporting_only FALSE
optimizer_adaptive_features TRUE
optimizer_inmemory_aware TRUE
-- Execution plan
SQL_ID 0f83zdknhqsmj, child number 6
-------------------------------------
SELECT CS_AUFTRAG_ID, CS_AUFPOS_SEQ, CS_AUFLIEF_SEQ, CS_AUFUNT_SEQ,
CS_AUFUNT_SEQ_BEFR, CS_HEFTFOLGE_ID, SEQNO, CS_HEFTFOLGE,
TO_CHAR(ACTUAL_PUB_DATE,'YYYY-MM-DD'),
TO_CHAR(CS_VSSOLL_DT,'YYYY-MM-DD'), TO_CHAR(CS_VSIST_DT,'YYYY-MM-DD'),
CS_ANZAHL_GEL, CS_MINLIEF, CS_YESNO_WV, CS_YESNO_LIEFERN,
CS_BEFRIST_CD, CS_UNTERBR_CD, CS_UDGRUND_CD, CS_YESNO_LIEFEINST,
CS_VERSART_CD, CS_KONDITION, CS_LIEFERMENGE, CS_PREIS, CURRENCY_CD,
CS_YESNO_TERMADR, CS_KDNR_AS400, CS_ADR_LINE_1, CS_YESNO_NACHLIEF,
TO_CHAR(CS_VSIST2_DT,'YYYY-MM-DD'), CS_ZUSTELLTYP_CD, CS_YN_HORIZONT
FROM PS_CS_HEFTEREIT_VW WHERE CS_AUFTRAG_ID=:1 AND CS_AUFPOS_SEQ=:2 AND
CS_AUFLIEF_SEQ=:3 ORDER BY CS_AUFTRAG_ID, CS_AUFPOS_SEQ,
CS_AUFLIEF_SEQ, SEQNO
Plan hash value: 4191856942
-----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 35 (100)| |
| 1 | SORT AGGREGATE | | 1 | 43 | | |
|* 2 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFLIEF_AU | 1 | 43 | 1 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | PSACS_AUFLIEF_AU | 1 | | 1 (0)| 00:00:01 |
| 4 | SORT ORDER BY | | 1 | 916 | 35 (9)| 00:00:01 |
|* 5 | FILTER | | | | | |
| 6 | NESTED LOOPS OUTER | | 1 | 916 | 31 (7)| 00:00:01 |
| 7 | NESTED LOOPS OUTER | | 1 | 866 | 30 (7)| 00:00:01 |
| 8 | NESTED LOOPS OUTER | | 1 | 798 | 29 (7)| 00:00:01 |
| 9 | NESTED LOOPS | | 1 | 708 | 28 (8)| 00:00:01 |
| 10 | NESTED LOOPS | | 1 | 640 | 27 (8)| 00:00:01 |
| 11 | NESTED LOOPS OUTER | | 1 | 550 | 26 (8)| 00:00:01 |
| 12 | NESTED LOOPS OUTER | | 1 | 512 | 25 (8)| 00:00:01 |
| 13 | NESTED LOOPS OUTER | | 1 | 469 | 24 (9)| 00:00:01 |
| 14 | NESTED LOOPS OUTER | | 1 | 411 | 23 (9)| 00:00:01 |
| 15 | VIEW | | 1 | 346 | 22 (10)| 00:00:01 |
| 16 | NESTED LOOPS OUTER | | 1 | 443 | 22 (10)| 00:00:01 |
|* 17 | VIEW | | 1 | 386 | 21 (10)| 00:00:01 |
| 18 | WINDOW SORT | | 1 | 540 | 21 (10)| 00:00:01 |
| 19 | NESTED LOOPS OUTER | | 1 | 540 | 20 (5)| 00:00:01 |
| 20 | NESTED LOOPS OUTER | | 1 | 488 | 19 (6)| 00:00:01 |
| 21 | NESTED LOOPS OUTER | | 1 | 424 | 18 (6)| 00:00:01 |
| 22 | NESTED LOOPS OUTER | | 1 | 374 | 17 (6)| 00:00:01 |
| 23 | NESTED LOOPS OUTER | | 1 | 322 | 16 (7)| 00:00:01 |
| 24 | VIEW | | 1 | 264 | 15 (7)| 00:00:01 |
| 25 | WINDOW BUFFER | | 1 | 254 | 15 (7)| 00:00:01 |
| 26 | VIEW | | 1 | 254 | 15 (7)| 00:00:01 |
| 27 | WINDOW SORT | | 1 | 532 | 15 (7)| 00:00:01 |
| 28 | NESTED LOOPS OUTER | | 1 | 532 | 13 (0)| 00:00:01 |
| 29 | NESTED LOOPS | | 1 | 503 | 12 (0)| 00:00:01 |
| 30 | NESTED LOOPS OUTER | | 1 | 474 | 11 (0)| 00:00:01 |
| 31 | NESTED LOOPS OUTER | | 1 | 445 | 10 (0)| 00:00:01 |
| 32 | NESTED LOOPS | | 1 | 390 | 9 (0)| 00:00:01 |
| 33 | NESTED LOOPS OUTER | | 1 | 303 | 8 (0)| 00:00:01 |
| 34 | NESTED LOOPS | | 1 | 258 | 7 (0)| 00:00:01 |
| 35 | NESTED LOOPS | | 1 | 240 | 6 (0)| 00:00:01 |
| 36 | NESTED LOOPS | | 1 | 198 | 5 (0)| 00:00:01 |
| 37 | NESTED LOOPS | | 1 | 171 | 4 (0)| 00:00:01 |
| 38 | VIEW | | 1 | 143 | 3 (0)| 00:00:01 |
| 39 | NESTED LOOPS | | 1 | 179 | 3 (0)| 00:00:01 |
| 40 | NESTED LOOPS | | 1 | 92 | 2 (0)| 00:00:01 |
| 41 | ROWID TABLE ACCESS BY INDEX | PS_CS_AUFTRAG_TB | 1 | 41 | 1 (0)| 00:00:01 |
|* 42 | INDEX UNIQUE SCAN | PS_CS_AUFTRAG_TB | 1 | | 1 (0)| 00:00:01 |
| 43 | ROWID TABLE ACCESS BY INDEX | PS_CS_AUFPOS_TB | 1 | 51 | 1 (0)| 00:00:01 |
|* 44 | INDEX UNIQUE SCAN | PS_CS_AUFPOS_TB | 1 | | 1 (0)| 00:00:01 |
| 45 | OWID TABLE ACCESS BY INDEX R | PS_CS_AUFLIEF_TB | 1 | 87 | 1 (0)| 00:00:01 |
|* 46 | INDEX UNIQUE SCAN | PS_CS_AUFLIEF_TB | 1 | | 1 (0)| 00:00:01 |
| 47 | ID TABLE ACCESS BY INDEX ROW | PS_CS_ARTIKEL_TB | 1 | 28 | 1 (0)| 00:00:01 |
|* 48 | INDEX UNIQUE SCAN | PS_CS_ARTIKEL_TB | 1 | | 1 (0)| 00:00:01 |
| 49 | D TABLE ACCESS BY INDEX ROWI | PS_CS_OBJEINW_TB | 1 | 27 | 1 (0)| 00:00:01 |
|* 50 | INDEX UNIQUE SCAN | PS_CS_OBJEINW_TB | 1 | | 1 (0)| 00:00:01 |
| 51 | TABLE ACCESS BY INDEX ROWID | PS_CS_MANDOBJ_TB | 1 | 42 | 1 (0)| 00:00:01 |
|* 52 | INDEX UNIQUE SCAN | PS_CS_MANDOBJ_TB | 1 | | 1 (0)| 00:00:01 |
| 53 | TABLE ACCESS BY INDEX ROWID | PS_CS_OBJSTEUER_TB | 1 | 18 | 1 (0)| 00:00:01 |
|* 54 | INDEX RANGE SCAN | PS_CS_OBJSTEUER_TB | 1 | | 1 (0)| 00:00:01 |
| 55 | SORT AGGREGATE | | 1 | 12 | | |
| 56 | FIRST ROW | | 1 | 12 | 1 (0)| 00:00:01 |
|* 57 | X) INDEX RANGE SCAN (MIN/MA | PS_CS_OBJSTEUER_TB | 1 | 12 | 1 (0)| 00:00:01 |
| 58 | TABLE ACCESS BY INDEX ROWID | PS_CS_AKT_PROD_TB | 1 | 45 | 1 (0)| 00:00:01 |
|* 59 | INDEX UNIQUE SCAN | PS_CS_AKT_PROD_TB | 1 | | 1 (0)| 00:00:01 |
|* 60 | TABLE ACCESS BY INDEX ROWID | PS_CS_HEFTFOLGE_TB | 6 | 522 | 1 (0)| 00:00:01 |
|* 61 | INDEX RANGE SCAN | PS_CS_HEFTFOLGE_TB | 2 | | 1 (0)| 00:00:01 |
| 62 | TABLE ACCESS BY INDEX ROWID | PS_CS_HEFTFOLGE_TB | 1 | 55 | 1 (0)| 00:00:01 |
|* 63 | INDEX UNIQUE SCAN | PS_CS_HEFTFOLGE_TB | 1 | | 1 (0)| 00:00:01 |
| 64 | TABLE ACCESS BY INDEX ROWID | PS_CS_HEFTFOLGE_TB | 1 | 29 | 1 (0)| 00:00:01 |
|* 65 | INDEX RANGE SCAN | PS0CS_HEFTFOLGE_TB | 1 | | 1 (0)| 00:00:01 |
| 66 | TABLE ACCESS BY INDEX ROWID | PS_CS_HEFTFOLGE_TB | 1 | 29 | 1 (0)| 00:00:01 |
|* 67 | INDEX RANGE SCAN | PS0CS_HEFTFOLGE_TB | 1 | | 1 (0)| 00:00:01 |
| 68 | TABLE ACCESS BY INDEX ROWID | PS_CS_HEFTFOLGE_TB | 1 | 29 | 1 (0)| 00:00:01 |
|* 69 | INDEX RANGE SCAN | PS0CS_HEFTFOLGE_TB | 1 | | 1 (0)| 00:00:01 |
|* 70 | TABLE ACCESS BY INDEX ROWID | PS_CS_SRY_REKLA_TB | 1 | 58 | 1 (0)| 00:00:01 |
|* 71 | INDEX RANGE SCAN | PSCCS_SRY_REKLA_TB | 1 | | 1 (0)| 00:00:01 |
|* 72 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFUNT_TB | 1 | 52 | 1 (0)| 00:00:01 |
|* 73 | INDEX RANGE SCAN | PS_CS_AUFUNT_TB | 1 | | 1 (0)| 00:00:01 |
|* 74 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFUNT_TB | 1 | 50 | 1 (0)| 00:00:01 |
|* 75 | INDEX RANGE SCAN | PS_CS_AUFUNT_TB | 1 | | 1 (0)| 00:00:01 |
|* 76 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFUNT_TB | 1 | 64 | 1 (0)| 00:00:01 |
|* 77 | INDEX RANGE SCAN | PS_CS_AUFUNT_TB | 1 | | 1 (0)| 00:00:01 |
|* 78 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFUNT_TB | 1 | 52 | 1 (0)| 00:00:01 |
|* 79 | INDEX RANGE SCAN | PS_CS_AUFUNT_TB | 1 | | 1 (0)| 00:00:01 |
|* 80 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFVERS_TB | 1 | 57 | 1 (0)| 00:00:01 |
|* 81 | INDEX RANGE SCAN | PS_CS_AUFVERS_TB | 2 | | 1 (0)| 00:00:01 |
| 82 | TABLE ACCESS BY INDEX ROWID | PS_CS_WVS_HFOLG_TB | 1 | 65 | 1 (0)| 00:00:01 |
|* 83 | INDEX UNIQUE SCAN | PS_CS_WVS_HFOLG_TB | 1 | | 1 (0)| 00:00:01 |
| 84 | TABLE ACCESS BY INDEX ROWID | PS_CS_VERSTRACK_TB | 1 | 58 | 1 (0)| 00:00:01 |
|* 85 | INDEX RANGE SCAN | PS1CS_VERSTRACK_TB | 1 | | 1 (0)| 00:00:01 |
|* 86 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFPOS_TB | 1 | 43 | 1 (0)| 00:00:01 |
|* 87 | INDEX RANGE SCAN | PSBCS_AUFPOS_TB | 1 | | 1 (0)| 00:00:01 |
| 88 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFLIEF_TB | 1 | 38 | 1 (0)| 00:00:01 |
|* 89 | INDEX RANGE SCAN | PS_CS_AUFLIEF_TB | 1 | | 1 (0)| 00:00:01 |
| 90 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFADR_TB | 1 | 90 | 1 (0)| 00:00:01 |
|* 91 | INDEX UNIQUE SCAN | PS_CS_AUFADR_TB | 1 | | 1 (0)| 00:00:01 |
| 92 | SORT AGGREGATE | | 1 | 49 | | |
|* 93 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFADR_TB | 1 | 49 | 1 (0)| 00:00:01 |
|* 94 | INDEX RANGE SCAN | PS_CS_AUFADR_TB | 1 | | 1 (0)| 00:00:01 |
| 95 | TABLE ACCESS BY INDEX ROWID | PS_CS_ADRART_TB | 1 | 68 | 1 (0)| 00:00:01 |
|* 96 | INDEX RANGE SCAN | PS_CS_ADRART_TB | 1 | | 1 (0)| 00:00:01 |
| 97 | SORT AGGREGATE | | 1 | 70 | | |
|* 98 | TABLE ACCESS BY INDEX ROWID | PS_CS_ADRART_TB | 1 | 70 | 1 (0)| 00:00:01 |
|* 99 | INDEX RANGE SCAN | PS_CS_ADRART_TB | 1 | | 1 (0)| 00:00:01 |
| 100 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFADR_TB | 1 | 90 | 1 (0)| 00:00:01 |
|*101 | INDEX RANGE SCAN | PS_CS_AUFADR_TB | 1 | | 1 (0)| 00:00:01 |
| 102 | TABLE ACCESS BY INDEX ROWID | PS_CS_ADRART_TB | 1 | 68 | 1 (0)| 00:00:01 |
|*103 | INDEX RANGE SCAN | PS_CS_ADRART_TB | 1 | | 1 (0)| 00:00:01 |
| 104 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFLIEFDT_TB | 1 | 50 | 1 (0)| 00:00:01 |
|*105 | INDEX RANGE SCAN | PS_CS_AUFLIEFDT_TB | 1 | | 1 (0)| 00:00:01 |
| 106 | SORT AGGREGATE | | 1 | 36 | | |
| 107 | FIRST ROW | | 1 | 36 | 1 (0)| 00:00:01 |
|*108 | INDEX RANGE SCAN (MIN/MAX) | PS_CS_AUFLIEFDT_TB | 1 | 36 | 1 (0)| 00:00:01 |
| 109 | SORT AGGREGATE | | 1 | 49 | | |
|*110 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFADR_TB | 1 | 49 | 1 (0)| 00:00:01 |
|*111 | INDEX RANGE SCAN | PS_CS_AUFADR_TB | 1 | | 1 (0)| 00:00:01 |
| 112 | SORT AGGREGATE | | 1 | 70 | | |
|*113 | TABLE ACCESS BY INDEX ROWID | PS_CS_ADRART_TB | 1 | 70 | 1 (0)| 00:00:01 |
|*114 | INDEX RANGE SCAN | PS_CS_ADRART_TB | 1 | | 1 (0)| 00:00:01 |
| 115 | SORT AGGREGATE | | 1 | 43 | | |
|*116 | FILTER | | | | | |
|*117 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFPOS_TB | 1 | 43 | 1 (0)| 00:00:01 |
|*118 | INDEX RANGE SCAN | PSBCS_AUFPOS_TB | 1 | | 1 (0)| 00:00:01 |
| 119 | SORT AGGREGATE | | 1 | 39 | | |
|*120 | TABLE ACCESS BY INDEX ROWID | PS_CS_AUFPOS_TB | 1 | 39 | 1 (0)| 00:00:01 |
|*121 | INDEX RANGE SCAN | PSBCS_AUFPOS_TB | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------------------
Note
-----
- dynamic statistics used: dynamic sampling (level=4)
- SQL plan baseline SQL_PLAN_3b0ugvyu8w97a4132b007 used for this statement
- statistics feedback used for this statement
In general, you can run this SQL:
select * from v$sql_shared_cursor
where sql_id = '0f83zdknhqsmj';
It will tell you why Oracle is not reusing the existing child cursors.
In your particular case, where you already seem to know that the reason for the non-reuse is that Oracle is re-optimizing the query because of cardinality mismatches, you can go right to this query:
select *
from V$SQL_REOPTIMIZATION_HINTS
where sql_id = '0f83zdknhqsmj';
That should give you insight into which plan step is involved in the cardinality mismatch.

Oracle 10g database optimization

Sorry for my English.
I have so big DB on Oracle 10g.
And I have queries, which executed so slow. For example, I have query :
115559 rows – 102 seconds
Execution plan:
Plan hash value: 3664903106
------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | SORT ORDER BY | | 1 | 30503 | 50 |00:00:09.33 | 3989 | 33M| 2065K| 29M (0)|
|* 2 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:05.71 | 3989 | 862K| 862K| 1186K (0)|
| 3 | INDEX FAST FULL SCAN | IX2_SLCND | 1 | 1387 | 1387 |00:00:00.01 | 17 | | | |
|* 4 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:05.47 | 3972 | 785K| 785K| 1145K (0)|
| 5 | TABLE ACCESS FULL | DISC | 1 | 90 | 90 |00:00:00.01 | 7 | | | |
|* 6 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:05.24 | 3965 | 776K| 776K| 403K (0)|
| 7 | VIEW | index$_join$_030 | 1 | 2 | 2 |00:00:00.01 | 6 | | | |
|* 8 | HASH JOIN | | 1 | | 2 |00:00:00.01 | 6 | 760K| 760K| 464K (0)|
| 9 | INDEX FAST FULL SCAN | IX_CMP_NAME | 1 | 2 | 2 |00:00:00.01 | 3 | | | |
| 10 | INDEX FAST FULL SCAN | PK_CMP | 1 | 2 | 2 |00:00:00.01 | 3 | | | |
|* 11 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:05.01 | 3959 | 756K| 756K| 1066K (0)|
| 12 | TABLE ACCESS FULL | TTYPE | 1 | 26 | 27 |00:00:00.01 | 7 | | | |
|* 13 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:04.78 | 3952 | 767K| 767K| 416K (0)|
| 14 | TABLE ACCESS FULL | COMMTCOMP | 1 | 2 | 2 |00:00:00.01 | 7 | | | |
|* 15 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:04.54 | 3945 | 760K| 760K| 1037K (0)|
| 16 | TABLE ACCESS FULL | TTYPE | 1 | 26 | 27 |00:00:00.01 | 7 | | | |
|* 17 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:04.31 | 3938 | 842K| 842K| 1267K (0)|
| 18 | TABLE ACCESS FULL | SLRSSEASONTC | 1 | 2885 | 2974 |00:00:00.01 | 53 | | | |
|* 19 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:04.07 | 3885 | 909K| 909K| 1178K (0)|
| 20 | TABLE ACCESS FULL | CAR | 1 | 976 | 976 |00:00:00.01 | 16 | | | |
|* 21 | HASH JOIN RIGHT OUTER | | 1 | 30503 | 115K|00:00:03.84 | 3869 | 1036K| 1036K| 1169K (0)|
| 22 | INDEX FULL SCAN | PK_STP | 1 | 258 | 258 |00:00:00.01 | 1 | | | |
|* 23 | HASH JOIN | | 1 | 30503 | 115K|00:00:03.60 | 3868 | 778K| 778K| 1165K (0)|
| 24 | TABLE ACCESS FULL | WKST | 1 | 83 | 83 |00:00:00.01 | 7 | | | |
|* 25 | HASH JOIN | | 1 | 61027 | 115K|00:00:03.37 | 3861 | 804K| 804K| 924K (0)|
| 26 | VIEW | index$_join$_014 | 1 | 12 | 12 |00:00:00.01 | 6 | | | |
|* 27 | HASH JOIN | | 1 | | 12 |00:00:00.01 | 6 | 783K| 783K| 919K (0)|
| 28 | INDEX FAST FULL SCAN | IX_BRANCH_NAME | 1 | 12 | 12 |00:00:00.01 | 3 | | | |
| 29 | INDEX FAST FULL SCAN | PK_BRANCH | 1 | 12 | 12 |00:00:00.01 | 3 | | | |
|* 30 | HASH JOIN | | 1 | 61027 | 115K|00:00:03.13 | 3855 | 808K| 808K| 1166K (0)|
| 31 | TABLE ACCESS FULL | USERS | 1 | 96 | 96 |00:00:00.01 | 16 | | | |
| 32 | MERGE JOIN | | 1 | 115K| 115K|00:00:02.90 | 3839 | | | |
|* 33 | HASH JOIN RIGHT OUTER| | 1 | 115K| 115K|00:00:02.32 | 3838 | 848K| 848K| 1169K (0)|
| 34 | TABLE ACCESS FULL | STP | 1 | 258 | 258 |00:00:00.01 | 7 | | | |
|* 35 | HASH JOIN | | 1 | 115K| 115K|00:00:01.95 | 3831 | 848K| 848K| 1169K (0)|
| 36 | TABLE ACCESS FULL | STP | 1 | 258 | 258 |00:00:00.01 | 7 | | | |
|* 37 | HASH JOIN | | 1 | 115K| 115K|00:00:01.52 | 3824 | 848K| 848K| 1169K (0)|
| 38 | TABLE ACCESS FULL | STP | 1 | 258 | 258 |00:00:00.01 | 7 | | | |
|* 39 | HASH JOIN | | 1 | 115K| 115K|00:00:01.09 | 3817 | 10M| 1956K| 12M (0)|
|* 40 | TABLE ACCESS FULL| SL | 1 | 116K| 120K|00:00:00.01 | 2115 | | | |
|* 41 | TABLE ACCESS FULL| SLTC | 1 | 114K| 115K|00:00:00.19 | 1702 | | | |
|* 42 | SORT JOIN | | 115K| 1 | 115K|00:00:00.27 | 1 | 73728 | 73728 | |
|* 43 | INDEX UNIQUE SCAN | PK_CMP | 1 | 1 | 1 |00:00:00.01 | 1 | | | |
------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("SLCND"."ID"="SL"."ID")
4 - access("SL"."DISC_ID"="DISC"."ID")
6 - access("CARI"."ID"="SLTC"."CARI_ID")
8 - access(ROWID=ROWID)
11 - access("TTYPE"."ID"="SLTC"."TTYPE_ID")
13 - access("CTC"."ID"="SLRSSEASONTC "."ID_COMMTCOMP")
15 - access("RS"."ID"="SLRSSEASONTC "."COMMTTYPE_ID")
17 - access("SLRSSEASONTC "."ID"="SLTC"."ID")
19 - access("CAR"."ID"="SLTC"."CAR_ID")
21 - access("STP"."ID"="WKST"."DEF_STP_ID")
23 - access("SL"."POS_WKST_ID"="WKST"."ID")
25 - access("USERS"."BRANCH_ID"="BRANCH"."ID")
27 - access(ROWID=ROWID)
30 - access("SL"."USR_CAS_ID"="USERS"."ID")
33 - access("SLTC"."THSTP_ID"="THSTP"."ID")
35 - access("SLTC"."TSTP_ID"="TSTP"."ID")
37 - access("SLTC"."FSTP_ID"="FSTP"."ID")
39 - access("SLTC"."ID"="SL"."ID")
40 - filter(("SL"."WHEN_DATE">=TO_DATE('2001-10-29 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND "SL"."SCOMP_ID"=1 AND
"SL"."WHEN_DATE"<=TO_DATE('2013-10-29 23:59:59', 'yyyy-mm-dd hh24:mi:ss')))
41 - filter("SLTC"."MANUAL"='N')
42 - access("SL"."SCOMP_ID"="CMP"."ID")
filter("SL"."SCOMP_ID"="CMP"."ID")
43 - access("CMP"."ID"=1)
I need ideas to make db faster.
Thanks You!
p.s.
I’m new in databases
So yeah, a you have a pretty horrible execution plan there.
To optimise the query, we would need the query as well, but I'll try to give you a few hints using just your exection plan output.
See all the TABLE ACCESS FULL? This is what usually takes time! Try using indexes on your tables, it seems that there are too few indexes used here (probably because no other indexes exist). Based on the execution plan, here are some simple indexes that might work, you may try them out:
CREATE INDEX ix_sltc_id ON sltc(ID);
CREATE INDEX ix_sl_id ON sl(ID);
CREATE INDEX ix_sltc_manual ON sltc(manual);
CREATE INDEX ix_sl_scomp_id ON sl(SCOMP_ID);
CREATE INDEX ix_sl_pos_wkst_id ON sl(POS_WKST_ID);
CREATE INDEX ix_sltc_thstp_id ON sltc(THSTP_ID)
CREATE INDEX ix_sltc_thstp_id ON sltc(THSTP_ID);
CREATE INDEX ix_sltc_tstp_id ON sltc(TSTP_ID);
CREATE INDEX ix_sltc_fstp_id ON sltc(FSTP_ID);
Without the query itself, we are quite limited here and probably missing most of the picture. Using the query, we could then try to create composite indexes, that are much more efficient.
More importantly, it seems that you do not use PRIMARY KEYs on your tables, because there are a lot of TABLE ACCESS FULL operations on tables with the predicate "ID". Make sure all your "ID" columns are indexed as well (or defined as PRIMARY KEY if that is indeed the primary key).
Also, we see that the optimizer does not have correct statistics, try to manually refresh the statistics for your schema:
EXEC DBMS_STATS.delete_schema_stats('SCOTT');
And as a sidenote: Whoever designed this schema, educate this person on database design!
Another sidenote for the more advanced readers: While TABLE ACCESS FULL is not always bad (there are quite a few cases where a full table scan is faster than access via indexes), it often indicates missing indexes. So setting the indexes and refreshing the statistics should provide a performance gain here.

Resources