I'm have the following code
WITH T AS(
SELECT SOMETHING
)
SELECT * FROM tab1 t1
LEFT JOIN tab2 t2 on t1.ID = t2 .ID
LEFT JOIN tab3 t3 on t1.ID = t3 .ID
LEFT JOIN tab4 t4 on t1.ID = t4.ID
LEFT JOIN tab5 t5 on t1.ID = t5.ID
INNER JOIN tempo_tab6 t6 on t1.ID = t6.ID
LEFT JOIN tab7 t7 on t1.ID = t7.ID
WHERE t1.Col1 = 0
AND t1.Col2 = 1
AND t1.Col3 IN (SELECT t8.Col FROM tab8 t8 WHERE Col ='ABC')
When I execute the Advisor, It advised me create FBI in ID.Col3, but my company rule isn't accept FBI In any case. Is there any way to solve this? It took 18s for some values without Index.
Many thanks.
Edit: this is the execution plan of this case.
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1976489795
-----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 873 | 11730 (1)| 00:00:01 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_1FD9EE041_D91A3E0 | | | | |
| 3 | HASH UNIQUE | | 1 | 436 | 15 (7)| 00:00:01 |
| 4 | MERGE JOIN CARTESIAN | | 1 | 436 | 14 (0)| 00:00:01 |
|* 5 | HASH JOIN OUTER | | 1 | 436 | 5 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
| 6 | NESTED LOOPS | | 1 | 220 | 3 (0)| 00:00:01 |
| 7 | NESTED LOOPS | | 1 | 217 | 3 (0)| 00:00:01 |
| 8 | NESTED LOOPS | | 1 | 209 | 2 (0)| 00:00:01 |
|* 9 | TABLE ACCESS FULL | TMP_REPORT | 1 | 204 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_STOCK_ID | 1 | 5 | 0 (0)| 00:00:01 |
|* 11 | INDEX RANGE SCAN | IX_LS_STOCK_ZONE_FK_STOCK_ID_FK_ZONE_ID | 1 | 8 | 1 (0)| 00:00:01 |
|* 12 | INDEX UNIQUE SCAN | PK_ZONE_ID | 1 | 3 | 0 (0)| 00:00:01 |
|* 13 | TABLE ACCESS FULL | TMP_REPORT | 1 | 216 | 2 (0)| 00:00:01 |
| 14 | BUFFER SORT | | 12727 | | 12 (0)| 00:00:01 |
| 15 | INDEX FAST FULL SCAN | PK_STOCK_DEPARTMENT_ID | 12727 | | 9 (0)| 00:00:01 |
| 16 | COUNT | | | | | |
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
|* 17 | HASH JOIN SEMI | | 1 | 873 | 11715 (1)| 00:00:01 |
| 18 | MERGE JOIN OUTER | | 1 | 669 | 11713 (1)| 00:00:01 |
| 19 | NESTED LOOPS OUTER | | 1 | 354 | 11709 (1)| 00:00:01 |
| 20 | NESTED LOOPS OUTER | | 1 | 284 | 11708 (1)| 00:00:01 |
| 21 | NESTED LOOPS OUTER | | 1 | 264 | 11707 (1)| 00:00:01 |
| 22 | NESTED LOOPS OUTER | | 1 | 237 | 11706 (1)| 00:00:01 |
| 23 | NESTED LOOPS OUTER | | 1 | 180 | 11705 (1)| 00:00:01 |
| 24 | NESTED LOOPS OUTER | | 1 | 166 | 11704 (1)| 00:00:01 |
| 25 | NESTED LOOPS OUTER | | 1 | 141 | 11703 (1)| 00:00:01 |
| 26 | NESTED LOOPS OUTER | | 1 | 123 | 11702 (1)| 00:00:01 |
|* 27 | HASH JOIN | | 1 | 100 | 11701 (1)| 00:00:01 |
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
| 28 | VIEW | | 1 | 26 | 2 (0)| 00:00:01 |
| 29 | TABLE ACCESS FULL | SYS_TEMP_1FD9EE041_D91A3E0 | 1 | 18 | 2 (0)| 00:00:01 |
|* 30 | TABLE ACCESS FULL | LS_ITEM_DETAILS | 870K| 61M| 11696 (1)| 00:00:01 |
| 31 | TABLE ACCESS BY INDEX ROWID| LS_ZONES | 1 | 23 | 1 (0)| 00:00:01 |
|* 32 | INDEX UNIQUE SCAN | PK_ZONE_ID | 1 | | 0 (0)| 00:00:01 |
| 33 | TABLE ACCESS BY INDEX ROWID | LS_INCIDENTS | 1 | 18 | 1 (0)| 00:00:01 |
|* 34 | INDEX UNIQUE SCAN | PK_INCIDENT_ID | 1 | | 0 (0)| 00:00:01 |
| 35 | TABLE ACCESS BY INDEX ROWID | LS_EMPLOYEES | 1 | 25 | 1 (0)| 00:00:01 |
|* 36 | INDEX UNIQUE SCAN | PK_EMPLOYEE_ID | 1 | | 0 (0)| 00:00:01 |
| 37 | TABLE ACCESS BY INDEX ROWID | LS_PROJECTS | 1 | 14 | 1 (0)| 00:00:01 |
|* 38 | INDEX UNIQUE SCAN | PK_PROJECT_ID | 1 | | 0 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
| 39 | TABLE ACCESS BY INDEX ROWID | LS_STOCKS | 1 | 57 | 1 (0)| 00:00:01 |
|* 40 | INDEX UNIQUE SCAN | PK_STOCK_ID | 1 | | 0 (0)| 00:00:01 |
| 41 | TABLE ACCESS BY INDEX ROWID | LS_PLANS | 1 | 27 | 1 (0)| 00:00:01 |
|* 42 | INDEX UNIQUE SCAN | PK_PLAN_ID | 1 | | 0 (0)| 00:00:01 |
| 43 | TABLE ACCESS BY INDEX ROWID | LS_GROUPS | 1 | 20 | 1 (0)| 00:00:01 |
|* 44 | INDEX UNIQUE SCAN | PK_GROUP_ID | 1 | | 0 (0)| 00:00:01 |
| 45 | TABLE ACCESS BY INDEX ROWID | LS_ITEMS | 1 | 70 | 1 (0)| 00:00:01 |
|* 46 | INDEX UNIQUE SCAN | ITEM_CODE_UNI | 1 | | 0 (0)| 00:00:01 |
| 47 | BUFFER SORT | | 2 | 630 | 11712 (1)| 00:00:01 |
| 48 | VIEW | VW_LAT_B17BD126 | 2 | 630 | 4 (0)| 00:00:01 |
| 49 | VIEW | VW_ORE_F374A3FE | 2 | 630 | 4 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
| 50 | UNION-ALL | | | | | |
|* 51 | FILTER | | | | | |
| 52 | TABLE ACCESS BY INDEX ROWID | LS_SUPPLIERS | 1 | 51 | 2 (0)| 00:00:01 |
|* 53 | INDEX UNIQUE SCAN | PK_SUPPLIER_ID | 1 | | 1 (0)| 00:00:01 |
|* 54 | FILTER | | | | | |
| 55 | TABLE ACCESS BY INDEX ROWID | LS_SUPPLIERS | 1 | 51 | 2 (0)| 00:00:01 |
|* 56 | INDEX UNIQUE SCAN | PK_SUPPLIER_ID | 1 | | 1 (0)| 00:00:01 |
|* 57 | TABLE ACCESS FULL | TMP_REPORT | 1 | 204 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------------------
The advisor suggest me create this FBI:
create index ISCHN.IDX$$_25380001 on ISCHN.LS_ITEM_DETAILS(SYS_OP_C2C("SERIAL"));
I have a 118 line query similar to this:
select * from (The inner query with many joins) WHERE campus_code IN ('560','598')
The campus_code is getting generated by a function f_get_bookstore(SSBSECT_TERM_CODE,SSBSECT_CRN) AS SSBSECT_CAMP_CODE in the inner query. If I run the inner query alone its count is 18 & it is getting executed in 13 s. But if I add the WHERE campus_code IN ('560','598') then it is taking more than 2 min.
Another strange thing is, I have another query which is also like
select * from (The inner query with many joins) WHERE campus_code IN ('560','598'). Here the inner query slightly different than previous one. The inner query is fast & returning 92 rows. But here the campus_code IN filtering is fast even though it is working on 92 rows (unlike 18 rows for the previous query). Here also the campus_code is generated through the same function.
Can any body help to tune the query? Please tell what more info do you need.
This is the entire query:
SELECT *
FROM
(SELECT 'columbusstate' bk_institution_id,
'columbusstate.'
|| scbcrse_subj_code
|| '.'
|| scbcrse_crse_numb
||'.'
|| Ssbsect_Crn
|| '.'
|| ssbsect_term_code bk_section_id,
ssbsect_camp_code AS campus_code,
scbcrse_subj_code
|| '.'
|| scbcrse_crse_numb
||'.'
|| Ssbsect_Crn
|| '.'
|| ssbsect_term_code institution_section_id,
ssbsect_crn short_description,
scbcrse_title AS description,
ssbsect_crn sections_ssbsect_crn,
ssbsect_term_code sections_ssbsect_term_code,
'na' instructor_first_name,
'na' instructor_last_name,
scbcrse_subj_code
|| '.'
|| scbcrse_crse_numb rel_institution_course_id,
scbcrse_title AS rel_course_description,
scbcrse_title AS rel_course_name,
scbcrse_crse_numb AS course_short_desc,
scbcrse_crse_numb course_number,
stvterm_desc term_short_desc,
stvterm_code rel_institution_term_id,
section.ssbsect_crn,
ssbsect_ssts_code AS ssbsect_ssts_code,
'columbusstate.'
|| stvterm_code rel_bk_term_id,
'columbusstate.'
|| scbcrse_subj_code
|| '.'
|| scbcrse_crse_numb rel_bk_course_id,
ssbsect_seq_numb,
ssbsect_enrl ssbsect_enrl,
ssbsect_enrl estimated_enrl,
ssbsect_max_enrl ssbsect_max_enrl,
ssbsect_crn ssbsect_section_key,
ssbsect_crn ssbsect_section_number,
'parent' relationship,
course.scbcrse_subj_code institution_department_id ,
'DFLT' institution_division_id,
'DFLT' division_short_desc
FROM
(SELECT *
FROM
(SELECT SSBSECT_TERM_CODE,
SSBSECT_CRN,
SSBSECT_SUBJ_CODE,
SSBSECT_CRSE_NUMB,
SSBSECT_PTRM_CODE,
SSBSECT_SEQ_NUMB,
SSBSECT_SSTS_CODE,
SSBSECT_MAX_ENRL,
SSBSECT_ENRL,
SSBSECT_PRNT_IND,
f_get_bookstore(SSBSECT_TERM_CODE,SSBSECT_CRN) AS SSBSECT_CAMP_CODE
FROM SSBSECT
) sect
JOIN
(SELECT *
FROM
(SELECT * FROM saturn.stvterm WHERE STVTERM_CODE >= '201401'
)
) term
ON term.stvterm_code=sect.ssbsect_term_code
) section
JOIN
(SELECT C1.scbcrse_subj_code,
C1.scbcrse_dept_code,
C1.scbcrse_crse_numb,
C1.scbcrse_title
FROM saturn.scbcrse C1
LEFT JOIN saturn.scbcrse C2
ON (C1.scbcrse_subj_code = C2.scbcrse_subj_code
AND C1.scbcrse_crse_numb = C2.scbcrse_crse_numb
AND C1.scbcrse_eff_term < C2.scbcrse_eff_term)
WHERE c2.scbcrse_eff_term IS NULL
) Course ON Course.scbcrse_subj_code = Section.ssbsect_subj_code
AND scbcrse_crse_numb = section.ssbsect_crse_numb
AND ssbsect_ssts_code IN ('A','V','X')
LEFT JOIN
(SELECT sirasgn_term_code sirasgn_term_code,
sirasgn_crn,
MAX(spriden_pidm) spriden_pidm,
MAX(spriden_first_name) instructor_first_name,
MAX(spriden_last_name) instructor_last_name
FROM
(SELECT Pidm spriden_pidm,
Csu_Id SPRIDEN_ID,
First_Name spriden_first_name,
Last_Name spriden_last_name,
Mi spriden_mi,
External_User_Id login,
Email
FROM Csuapps.Wfollett_Person
) persons
JOIN
( SELECT * FROM saturn.sirasgn WHERE SIRASGN_PRIMARY_IND = 'Y'
) relations
ON persons.spriden_pidm=relations.sirasgn_pidm
GROUP BY sirasgn_crn,
sirasgn_term_code
) instr ON section.ssbsect_term_code=instr.sirasgn_term_code
AND section.ssbsect_crn =instr.sirasgn_crn
WHERE Course.scbcrse_subj_code = 'ACCT'
AND section.ssbsect_term_code = '201702'
)
WHERE campus_code IN ('560','1157')
Execution Plan:
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2063389120
-----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 77 | 968K| | 4364 (3)| 00:00:01 |
| 1 | SORT ORDER BY | | 77 | 968K| 624K| 4364 (3)| 00:00:01 |
|* 2 | VIEW | | 77 | 968K| | 4155 (3)| 00:00:01 |
| 3 | COUNT | | | | | | |
| 4 | VIEW | | 77 | 967K| | 4155 (3)| 00:00:01 |
| 5 | SORT ORDER BY | | 77 | 774K| | 4155 (3)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|* 6 | FILTER | | | | | | |
|* 7 | HASH JOIN RIGHT OUTER | | 77 | 774K| | 4154 (3)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | SCBCRSE_KEY_INDEX | 83 | 1494 | | 1 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | 77 | 772K| | 4153 (3)| 00:00:01 |
| 10 | NESTED LOOPS OUTER | | 23 | 229K| | 4139 (3)| 00:00:01 |
|* 11 | HASH JOIN OUTER | | 23 | 1656 | | 3783 (1)| 00:00:01 |
| 12 | NESTED LOOPS | | 23 | 1334 | | 7 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID | STVTERM | 1 | 22 | | 1 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | PK_STVTERM | 1 | | | 1 (0)| 00:00:01 |
|* 15 | TABLE ACCESS BY INDEX ROWID BATCHED| SSBSECT | 23 | 828 | | 6 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | SSBSECT_INDEX_SUBJ | 25 | | | 1 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 17 | VIEW | | 2172 | 30408 | | 3775 (1)| 00:00:01 |
| 18 | HASH GROUP BY | | 2172 | 8537K| 16M| 3775 (1)| 00:00:01 |
|* 19 | HASH JOIN | | 4166 | 15M| | 1364 (1)| 00:00:01 |
| 20 | VIEW | VW_GBF_14 | 2312 | 18496 | | 211 (1)| 00:00:01 |
| 21 | HASH GROUP BY | | 2312 | 48552 | | 211 (1)| 00:00:01 |
|* 22 | TABLE ACCESS FULL | SIRASGN | 2312 | 48552 | | 210 (1)| 00:00:01 |
| 23 | VIEW | WFOLLETT_PERSON | 3714 | 14M| | 1153 (1)| 00:00:01 |
| 24 | SORT UNIQUE | | 3714 | 342K| | 1153 (1)| 00:00:01 |
| 25 | UNION-ALL | | | | | | |
| 26 | NESTED LOOPS | | 1 | 59 | | 2 (0)| 00:00:01 |
| 27 | NESTED LOOPS | | 1 | 59 | | 2 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|* 28 | INDEX RANGE SCAN | PK_GLBEXTR | 1 | 38 | | 1 (0)| 00:00:01 |
|* 29 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
| 30 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
| 31 | NESTED LOOPS | | 1912 | 130K| | 605 (0)| 00:00:01 |
| 32 | NESTED LOOPS | | 1912 | 130K| | 605 (0)| 00:00:01 |
|* 33 | HASH JOIN | | 1912 | 93688 | | 31 (0)| 00:00:01 |
| 34 | VIEW | VW_SQ_2 | 3076 | 83052 | | 10 (0)| 00:00:01 |
| 35 | HASH GROUP BY | | 3076 | 39988 | | 10 (0)| 00:00:01 |
| 36 | INDEX FULL SCAN | PK_SIBINST | 6243 | 81159 | | 10 (0)| 00:00:01 |
|* 37 | TABLE ACCESS FULL | SIBINST | 3881 | 85382 | | 21 (0)| 00:00:01 |
|* 38 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 39 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
| 40 | NESTED LOOPS | | 1801 | 41423 | | 543 (1)| 00:00:01 |
| 41 | NESTED LOOPS | | 1801 | 41423 | | 543 (1)| 00:00:01 |
| 42 | VIEW | VW_DTP_6100A9C4 | 1801 | 3602 | | 3 (34)| 00:00:01 |
| 43 | HASH UNIQUE | | 1801 | 23413 | | 3 (34)| 00:00:01 |
|* 44 | INDEX RANGE SCAN | PK_SIRASGN | 4161 | 54093 | | 2 (0)| 00:00:01 |
|* 45 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
| 46 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
| 47 | VIEW PUSHED PREDICATE | | 1 | 10165 | | 16 (25)| 00:00:01 |
|* 48 | FILTER | | | | | | |
| 49 | NESTED LOOPS | | 1 | 10164 | | 16 (25)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 50 | NESTED LOOPS | | 1 | 79 | | 4 (0)| 00:00:01 |
|* 51 | FILTER | | | | | | |
| 52 | NESTED LOOPS OUTER | | 1 | 60 | | 3 (0)| 00:00:01 |
| 53 | NESTED LOOPS | | 1 | 42 | | 2 (0)| 00:00:01 |
| 54 | TABLE ACCESS BY INDEX ROWID | SSBSECT | 1 | 24 | | 1 (0)| 00:00:01 |
|* 55 | INDEX UNIQUE SCAN | PK_SSBSECT | 1 | | | 1 (0)| 00:00:01 |
|* 56 | INDEX RANGE SCAN | SCBCRSE_KEY_INDEX | 1 | 18 | | 1 (0)| 00:00:01 |
|* 57 | INDEX RANGE SCAN | SCBCRSE_KEY_INDEX | 15046 | 264K| | 1 (0)| 00:00:01 |
|* 58 | INDEX RANGE SCAN | PK_SIRASGN | 1 | 19 | | 1 (0)| 00:00:01 |
| 59 | VIEW | WFOLLETT_PERSON | 1 | 10085 | | 12 (34)| 00:00:01 |
| 60 | SORT UNIQUE | | 3 | 304 | | 12 (34)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 61 | UNION ALL PUSHED PREDICATE | | | | | | |
| 62 | NESTED LOOPS | | 1 | 59 | | 2 (0)| 00:00:01 |
| 63 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
|* 64 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
|* 65 | INDEX RANGE SCAN | PK_GLBEXTR | 1 | 38 | | 1 (0)| 00:00:01 |
| 66 | NESTED LOOPS | | 1 | 70 | | 3 (0)| 00:00:01 |
| 67 | NESTED LOOPS | | 1 | 70 | | 3 (0)| 00:00:01 |
| 68 | NESTED LOOPS | | 1 | 48 | | 2 (0)| 00:00:01 |
| 69 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
|* 70 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
| 71 | VIEW | VW_SQ_1 | 1 | 27 | | 1 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 72 | SORT GROUP BY | | 1 | 13 | | 1 (0)| 00:00:01 |
|* 73 | INDEX RANGE SCAN | PK_SIBINST | 2 | 26 | | 1 (0)| 00:00:01 |
|* 74 | INDEX UNIQUE SCAN | PK_SIBINST | 1 | | | 1 (0)| 00:00:01 |
|* 75 | TABLE ACCESS BY INDEX ROWID | SIBINST | 1 | 22 | | 1 (0)| 00:00:01 |
| 76 | NESTED LOOPS | | 1 | 23 | | 4 (25)| 00:00:01 |
| 77 | TABLE ACCESS BY INDEX ROWID | GOBTPAC | 1 | 21 | | 1 (0)| 00:00:01 |
|* 78 | INDEX UNIQUE SCAN | PK_GOBTPAC | 1 | | | 1 (0)| 00:00:01 |
|* 79 | VIEW | VW_DTP_32C68FB6 | 1 | 2 | | 3 (34)| 00:00:01 |
| 80 | SORT UNIQUE | | 2 | 26 | | 3 (34)| 00:00:01 |
|* 81 | INDEX RANGE SCAN | PK_SIRASGN | 2 | 26 | | 2 (0)| 00:00:01 |
| 82 | TABLE ACCESS BY INDEX ROWID BATCHED | SCBCRSE | 3 | 126 | | 1 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|* 83 | INDEX RANGE SCAN | SCBCRSE_KEY_INDEX | 1 | | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("from$_subquery$_002"."CAMPUS_CODE"='1157' OR "from$_subquery$_002"."CAMPUS_CODE"='560') AND "R">=1
AND "R"<=1500)
6 - filter("C2"."SCBCRSE_EFF_TERM" IS NULL)
7 - access("C1"."SCBCRSE_SUBJ_CODE"="C2"."SCBCRSE_SUBJ_CODE"(+) AND
"C1"."SCBCRSE_CRSE_NUMB"="C2"."SCBCRSE_CRSE_NUMB"(+))
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
filter("C1"."SCBCRSE_EFF_TERM"<"C2"."SCBCRSE_EFF_TERM"(+))
8 - access("C2"."SCBCRSE_SUBJ_CODE"(+)='ACCT')
11 - access("SSBSECT_TERM_CODE"="INSTR"."SIRASGN_TERM_CODE"(+) AND "SSBSECT_CRN"="INSTR"."SIRASGN_CRN"(+))
14 - access("STVTERM"."STVTERM_CODE"='201702')
15 - filter("SSBSECT_SSTS_CODE"='A' OR "SSBSECT_SSTS_CODE"='V' OR "SSBSECT_SSTS_CODE"='X')
16 - access("SSBSECT_SUBJ_CODE"='ACCT' AND "SSBSECT_TERM_CODE"='201702')
filter("SSBSECT_TERM_CODE"='201702')
19 - access("PIDM"="ITEM_1")
22 - filter("SIRASGN"."SIRASGN_TERM_CODE"='201702' AND "SIRASGN_PRIMARY_IND"='Y')
28 - access("GLBEXTR_APPLICATION"='STUDENT' AND "GLBEXTR_SELECTION"='CURR_ENRL' AND "GLBEXTR_CREATOR_ID"='GSHOUL')
29 - access("GOBTPAC_PIDM"=TO_NUMBER("GLBEXTR_KEY"))
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
33 - access("A"."SIBINST_TERM_CODE_EFF"="MAX(B.SIBINST_TERM_CODE_EFF)" AND "ITEM_2"="A"."SIBINST_PIDM")
37 - filter("A"."SIBINST_FCST_CODE"='AC' AND "A"."SIBINST_FCTG_CODE"<>'EMPL')
38 - access("A"."SIBINST_PIDM"="GOBTPAC_PIDM")
44 - access("SIRASGN_TERM_CODE">="TOOLS"."GETTERMCODE"(NULL,SYSDATE#!))
45 - access("ITEM_1"="GOBTPAC_PIDM")
48 - filter("SSBSECT_TERM_CODE">='201602' AND "SSBSECT_TERM_CODE"='201702')
51 - filter("C2"."SCBCRSE_EFF_TERM" IS NULL)
55 - access("SSBSECT_TERM_CODE"="SSBSECT_TERM_CODE" AND "SSBSECT_CRN"="SSBSECT_CRN")
filter("SSBSECT_TERM_CODE"='201702')
56 - access("SSBSECT_SUBJ_CODE"="C1"."SCBCRSE_SUBJ_CODE" AND "SSBSECT_CRSE_NUMB"="C1"."SCBCRSE_CRSE_NUMB")
57 - access("C1"."SCBCRSE_SUBJ_CODE"="C2"."SCBCRSE_SUBJ_CODE"(+) AND
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
"C1"."SCBCRSE_CRSE_NUMB"="C2"."SCBCRSE_CRSE_NUMB"(+) AND "C1"."SCBCRSE_EFF_TERM"<"C2"."SCBCRSE_EFF_TERM"(+) AND
"C2"."SCBCRSE_EFF_TERM"(+) IS NOT NULL)
58 - access("REL"."SIRASGN_TERM_CODE"="SSBSECT_TERM_CODE" AND "REL"."SIRASGN_CRN"="SSBSECT_CRN")
filter("REL"."SIRASGN_TERM_CODE"="SSBSECT_TERM_CODE" AND "REL"."SIRASGN_TERM_CODE"='201702' AND
"REL"."SIRASGN_CRN"="SSBSECT_CRN")
64 - access("GOBTPAC_PIDM"="REL"."SIRASGN_PIDM")
65 - access("GLBEXTR_APPLICATION"='STUDENT' AND "GLBEXTR_SELECTION"='CURR_ENRL' AND "GLBEXTR_CREATOR_ID"='GSHOUL')
filter(TO_NUMBER("GLBEXTR_KEY")="REL"."SIRASGN_PIDM" AND "GOBTPAC_PIDM"=TO_NUMBER("GLBEXTR_KEY"))
70 - access("GOBTPAC_PIDM"="REL"."SIRASGN_PIDM")
73 - access("B"."SIBINST_PIDM"="REL"."SIRASGN_PIDM")
74 - access("A"."SIBINST_PIDM"="REL"."SIRASGN_PIDM" AND "A"."SIBINST_TERM_CODE_EFF"="MAX(B.SIBINST_TERM_CODE_EFF)")
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
filter("A"."SIBINST_PIDM"="GOBTPAC_PIDM" AND "ITEM_1"="A"."SIBINST_PIDM")
75 - filter("A"."SIBINST_FCST_CODE"='AC' AND "A"."SIBINST_FCTG_CODE"<>'EMPL')
78 - access("GOBTPAC_PIDM"="REL"."SIRASGN_PIDM")
79 - filter("ITEM_1"="GOBTPAC_PIDM")
81 - access("SIRASGN_TERM_CODE">="TOOLS"."GETTERMCODE"(NULL,SYSDATE#!) AND "SIRASGN_PIDM"="REL"."SIRASGN_PIDM")
filter("SIRASGN_PIDM"="REL"."SIRASGN_PIDM")
83 - access("C1"."SCBCRSE_SUBJ_CODE"='ACCT' AND "C1"."SCBCRSE_CRSE_NUMB"="SSBSECT_CRSE_NUMB")
139 rows selected.
The performance of your query depends on the details, that we don't know, and on the joins. In general, if the joins result in a huge set of rows, that will eat a lot of cpu and ram. So try to add where clauses that minimize the number of rows in the joins.
Said in an other way, just imagine you are the cpu. Go through your query and try to estimate the number of rows that you need to process, and how you could limit that number of rows.
Are you using an index on crucial tables to speed up selects? Are you modifying the search column used in an index, so that the index does not work? Stuff like this is very important.
Good luck!
update:
The plan shows to me that most cpu is burned for the outermost query, something that you already noticed in the timing measurements. My strategy would be to try to move the outermost where-clause towards the inner queries. If the database engine can apply the where-clause in an earlier phase, the query will need less memory and cpu.
Now it is not possible to see to which table each output field belongs. If I where you I would give EVERY table in each FROM an alias.
For the sake of testing performance, and for posting here, you could simplify the lists of output fields. Leave out fields that are not required by outer queries, or use asterisk. Also, try to present a perfectly pretty printed query.
Apart from the Plan, could you get some info on memory usage? With the outer query, perhaps it needs to get a lot of data in memory before outputting results. Just imagine if this results in exhausting ram and needs swap, that will cost a lot of time. Memory use may also come from holding a lock on possibly big tables, so do not get fooled by your 'just 18 rows' of output.
OK, I'm going to put this in a "answer", since comments seem to be ignored.
The only way to know what is going on and how to fix your problem is to get the execution plan. Otherwise every answer is a guess. You may get lucky that a guess works, but then you will never know why. So please help us to help you.
To get an execution plan (for both the queries with and without the WHERE clause), run this after your query...
set lines 500
set pages 10000
select * from table( dbms_xplan.display_cursor( null, null, 'TYPICAL' ));
Is campus_code an integer? If it is, try removing the apostrophes, like this:
WHERE campus_code IN (560,598)
Otherwise, each value gets converted before being compared, and that can take a lot of time.
Hope this helps.
What you observe is by 99% a merging predicates in an inline view.
This works typically fine and helps performance as illustrated on an example below.
Sample Data
create table T1 as
select 'xxxx'||rownum crampus_code from dual connect by level <= 100000;
create index idx1 on t1(crampus_code);
This query can take a substantial time on a large table as the whole table must be accessed.
select crampus_code, count(*) from T1 group by crampus_code;
A following query using the previous query as a subquery can be very effective. How?
The WHERE clause in MERGE in the subquery and only the data for the two keys are accessed (index) and aggregated.
with agg as
(
select
a.crampus_code, count(*)
from
T1 a
group by
crampus_code
)
select *
from agg
where crampus_code in ('xxxx42','xxxx399');
The proof is in the execution plan (that you don't provided)
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 48 | 3 (0)| 00:00:01 |
| 1 | SORT GROUP BY NOSORT| | 2 | 48 | 3 (0)| 00:00:01 |
| 2 | INLIST ITERATOR | | | | | |
|* 3 | INDEX RANGE SCAN | IDX1 | 2 | 48 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("A"."CRAMPUS_CODE"='xxxx399' OR
"A"."CRAMPUS_CODE"='xxxx42')
You see the table is accesse via index for only the two keys.
Your Case
This is only speculation but IMO during the merge predicate phase you get a much worst execution plan that without it.
This explain the increase in elapsed time by addin the WHERE clause.
Only if you show both plans (subquery and the query with WHERE) you can be sure...
Workaround
So what can you do if the predicate merge destroys the performance?
Simple turn it off. Unfortunately you must use an undocumented hint MATERIALIZE, that set up the result of the query as temporary table
and the WHERE predicate will be applied on it.
This should work for your 18 rows. I'm not sure, but thing you must rewrite query using the subquery factoring (WITH).
with agg as
(select /*+ MATERIALIZE */ a.crampus_code, count(*) from T1 a group by crampus_code)
select * from agg
where crampus_code in ('xxxx42','xxxx399');
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 97325 | 3516K| 94 (5)| 00:00:02 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D673A_CE046F62 | | | | |
| 3 | HASH GROUP BY | | 97325 | 2281K| 41 (10)| 00:00:01 |
| 4 | TABLE ACCESS FULL | T1 | 97325 | 2281K| 37 (0)| 00:00:01 |
|* 5 | VIEW | | 97325 | 3516K| 54 (2)| 00:00:01 |
| 6 | TABLE ACCESS FULL | SYS_TEMP_0FD9D673A_CE046F62 | 97325 | 2281K| 54 (2)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - filter("CRAMPUS_CODE"='xxxx399' OR "CRAMPUS_CODE"='xxxx42')
I'm having a hard time optimising a sql query that takes about 1 min to complete. Here is the query :
SELECT mpg.ID_PROD_GARN, mpg.NO_PROD
FROM ACO.prime p
JOIN ACO.facture_compt fc
ON fc.id_factr = p.id_factr
JOIN ACO.V_CONTRAT vc
ON vc.NO_POLC = p.NO_POLC
JOIN ACO.MV_PRODUIT mp
ON mp.NO_PROD =vc.NO_PROD
JOIN ACO.MV_PROD_GARN mpg
ON mpg.NO_PROD = mp.NO_PROD
WHERE p.id_prime =
( SELECT MAX(id_prime) AS prime FROM ACO.prime p WHERE p.no_polc='T3167978')
AND mpg.ID_PROD_GARN = '1238'
AND fc.cd_stat_factr = 'comp';
V_CONTRAT is a view and (if my understanding is correct) when joining the view in this way SQL is running trough all the rows to find the result. I did a bit of research and found that indexing this view could speed up my query. So :
CREATE INDEX indx_no_produit ON ACO.V_CONTRAT(NO_PROD);
Unfortunately I get an error saying that I can't index a view SQL : ORA-01702 : you can't use that here.
*Cause: Among other possible causes, this message will be produced if an
attempt was made to define an Editioning View over a view.
*Action: An Editioning View may only be created over a base table.
So my question is how could I speed up this query elegantly?
Many thanks in advance!
Edit 1 : here is the explained plan
Plan hash value: 3107129748
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 102 | | 543K (1)| 00:00:22 |
| 1 | NESTED LOOPS | | 1 | 102 | | 543K (1)| 00:00:22 |
| 2 | NESTED LOOPS | | 1 | 90 | | 543K (1)| 00:00:22 |
| 3 | NESTED LOOPS | | 1 | 35 | | 3 (0)| 00:00:01 |
| 4 | NESTED LOOPS | | 1 | 14 | | 2 (0)| 00:00:01 |
| 5 | MAT_VIEW ACCESS BY INDEX ROWID| MV_PROD_GARN | 1 | 9 | | 1 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_PROG | 1 | | | 1 (0)| 00:00:01 |
| 7 | BITMAP CONVERSION TO ROWIDS | | 1 | 5 | | 1 (0)| 00:00:01 |
|* 8 | BITMAP INDEX FAST FULL SCAN | MV_PROD_NO_PROD_IDX | | | | | |
| 9 | TABLE ACCESS BY INDEX ROWID | PRIME | 1 | 21 | | 1 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_PRIME | 1 | | | 1 (0)| 00:00:01 |
| 11 | SORT AGGREGATE | | 1 | 15 | | | |
| 12 | FIRST ROW | | 1 | 15 | | 1 (0)| 00:00:01 |
|* 13 | INDEX RANGE SCAN (MIN/MAX) | PRIME_NO_POLC_IDX | 1 | 15 | | 1 (0)| 00:00:01 |
|* 14 | VIEW | V_CONTRAT | 1 | 55 | | 543K (1)| 00:00:22 |
| 15 | SORT UNIQUE | | 16M| 5011M| 2740M| 543K (1)| 00:00:22 |
| 16 | UNION-ALL | | | | | | |
|* 17 | HASH JOIN | | 16M| 2502M| | 55963 (4)| 00:00:03 |
| 18 | VIEW | index$_join$_016 | 103 | 1339 | | 2 (0)| 00:00:01 |
|* 19 | HASH JOIN | | | | | | |
| 20 | INDEX FAST FULL SCAN | PK_PROD | 103 | 1339 | | 1 (0)| 00:00:01 |
| 21 | INDEX FAST FULL SCAN | PRODUIT_COMBINE_IDX | 103 | 1339 | | 1 (0)| 00:00:01 |
|* 22 | HASH JOIN RIGHT OUTER | | 16M| 2293M| 261M| 55860 (4)| 00:00:03 |
| 23 | INDEX FAST FULL SCAN | ROL_INDEX1 | 10M| 145M| | 5703 (2)| 00:00:01 |
|* 24 | HASH JOIN RIGHT OUTER | | 6751K| 824M| 117M| 44540 (4)| 00:00:02 |
| 25 | INLIST ITERATOR | | | | | | |
|* 26 | INDEX RANGE SCAN | ROL_CDROL_NOINTR_IDX | 3975K| 72M| | 756 (2)| 00:00:01 |
|* 27 | HASH JOIN RIGHT OUTER | | 4192K| 435M| 90M| 40898 (3)| 00:00:02 |
|* 28 | TABLE ACCESS FULL | ROLE | 2881K| 57M| | 14553 (4)| 00:00:01 |
|* 29 | HASH JOIN | | 2941K| 246M| 104M| 24558 (3)| 00:00:01 |
| 30 | INDEX FAST FULL SCAN | INFO_BASE_DISTRIBUTEUR_FK1 | 4047K| 57M| | 1925 (2)| 00:00:01 |
|* 31 | HASH JOIN | | 2961K| 206M| 136M| 20967 (3)| 00:00:01 |
| 32 | TABLE ACCESS FULL | CONTRAT_ITER | 4088K| 89M| | 12159 (2)| 00:00:01 |
|* 33 | HASH JOIN RIGHT OUTER | | 2961K| 141M| 32M| 7292 (3)| 00:00:01 |
|* 34 | INDEX RANGE SCAN | ROL_CDROL_NOINTR_IDX | 933K| 22M| | 890 (1)| 00:00:01 |
|* 35 | TABLE ACCESS FULL | CONTRAT | 2615K| 62M| | 5781 (3)| 00:00:01 |
|* 36 | HASH JOIN OUTER | | 29239 | 2912K| | 10228 (3)| 00:00:01 |
|* 37 | HASH JOIN | | 29239 | 1941K| | 285 (2)| 00:00:01 |
| 38 | TABLE ACCESS FULL | DISTRIBUTEUR | 9142 | 91420 | | 45 (3)| 00:00:01 |
|* 39 | HASH JOIN | | 29239 | 1656K| | 240 (1)| 00:00:01 |
| 40 | INDEX FULL SCAN | PRODUIT_COMBINE_IDX | 103 | 1030 | | 1 (0)| 00:00:01 |
|* 41 | TABLE ACCESS FULL | TPA_CONTRAT_MENSUEL | 29239 | 1370K| | 239 (1)| 00:00:01 |
| 42 | TABLE ACCESS FULL | COUNTERPARTY | 3547K| 115M| | 9921 (2)| 00:00:01 |
|* 43 | INDEX RANGE SCAN | FACTURE_COMPT_INDEX9 | 1 | 12 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("MPG"."ID_PROD_GARN"=1238)
8 - filter("MPG"."NO_PROD"="MP"."NO_PROD")
10 - access("P"."ID_PRIME"= (SELECT MAX("ID_PRIME") FROM "ACO"."PRIME" "P" WHERE "P"."NO_POLC"='T3167978'))
13 - access("P"."NO_POLC"='T3167978')
14 - filter("VC"."NO_POLC"="P"."NO_POLC" AND "MP"."NO_PROD"="VC"."NO_PROD")
17 - access("PROD"."NO_PROD"="ITER"."NO_PROD" AND "PROD"."NO_VERS_PROD"="ITER"."NO_VERS_PROD")
19 - access(ROWID=ROWID)
22 - access("ROLAUTRE"."ID_CONT"(+)="CONT"."ID_CONT" AND "ROLAUTRE"."NO_ITER_CONT"(+)="CONT"."NO_DERN_ITER")
24 - access("ROLA"."ID_CONT"(+)="CONT"."ID_CONT" AND "ROLA"."NO_ITER_CONT"(+)="CONT"."NO_DERN_ITER")
26 - access("ROLA"."CD_ROLE"(+)='ap' OR "ROLA"."CD_ROLE"(+)='debit' OR "ROLA"."CD_ROLE"(+)='emprun')
27 - access("ROLPAY"."ID_CONT"(+)="CONT"."ID_CONT" AND "ROLPAY"."NO_ITER_CONT"(+)="CONT"."NO_DERN_ITER")
28 - filter("ROLPAY"."CD_ROLE"(+)='pay' AND "ROLPAY"."IND_PAY_PRI"(+)='1')
29 - access("ITER"."ID_INFO_BASE"="IB"."ID_INFO_BASE" AND "ITER"."NO_ITER_CONT"="IB"."NO_ITER_CONT" AND
SYS_OP_DESCEND("ITER"."NO_ITER_CONT")=SYS_OP_DESCEND("IB"."NO_ITER_CONT"))
31 - access("ITER"."ID_CONT"="CONT"."ID_CONT" AND "ITER"."NO_ITER_CONT"="CONT"."NO_DERN_ITER" AND
SYS_OP_DESCEND("ITER"."NO_ITER_CONT")=SYS_OP_DESCEND("CONT"."NO_DERN_ITER"))
33 - access("ROLP"."ID_CONT"(+)="CONT"."ID_CONT" AND "ROLP"."NO_ITER_CONT"(+)="CONT"."NO_DERN_ITER")
34 - access("ROLP"."CD_ROLE"(+)='pren')
35 - filter("CONT"."NO_SEQ_PROPO_SEL"=0)
36 - access("CTRPY"."LAST_NAME"(+)="TCM"."CON_NOM_ASS_PRINC" AND
"CTRPY"."FRST_NAME"(+)="TCM"."CON_PRENOM_ASS_PRINC" AND "CTRPY"."DT_BIRTH"(+)="TCM"."CON_DATE_NAISS_ASS_PRINC")
37 - access("TCM"."CON_NO_DISTRIBUTEUR"="A"."NO_DIST")
39 - access("PROD"."NO_PROD"="TCM"."CON_CODE_PRODDUIT")
41 - filter("TCM"."CON_VERSION_CONTRAT"=1)
43 - access("FC"."ID_FACTR"="P"."ID_FACTR" AND "FC"."CD_STAT_FACTR"='comp')
Edit 2 : Here is the view V_CONTRAT
SELECT DISTINCT cont.ID_CONT,
cont.NO_POLC,
cont.cd_divs,
prod.no_prod,
prod.cd_cie_encai,
prod.cd_faml_cptb,
ib.no_dist_init,
CASE
WHEN ROLP.ID_ROLE IS NOT NULL THEN ROLP.NO_INTR
WHEN rola.no_intr IS NOT NULL THEN rola.no_intr
WHEN rolpay.no_intr IS NOT NULL THEN rolpay.no_intr
ELSE rolAutre.no_intr
END
AS NO_INTR_PRINC,
rolpay.no_intr AS NO_INTR_PAY
FROM VIRAGE.CONTRAT CONT
INNER JOIN
VIRAGE.contrat_iter iter
ON iter.id_cont = cont.id_cont
AND ITER.NO_ITER_CONT = CONT.NO_DERN_ITER
AND CONT.NO_SEQ_PROPO_SEL = 0
INNER JOIN
VIRAGE.info_base ib
ON iter.id_info_base = ib.id_info_base
AND iter.no_iter_cont = ib.no_iter_cont
INNER JOIN
VIRAGE.produit prod
ON prod.no_prod = iter.no_prod
AND prod.no_vers_prod = iter.no_vers_prod
LEFT JOIN
VIRAGE.role rolp
ON rolp.id_cont = cont.id_cont
AND rolp.no_iter_cont = cont.no_dern_iter
AND rolp.cd_role = 'pren'
LEFT JOIN
VIRAGE.role rola
ON rola.id_cont = cont.id_cont
AND rola.no_iter_cont = cont.no_dern_iter
AND ( rola.cd_role = 'ap'
OR ROLA.CD_ROLE = 'debit'
OR rola.cd_role = 'emprun')
LEFT JOIN
VIRAGE.role rolpay
ON rolpay.id_cont = cont.id_cont
AND rolpay.no_iter_cont = cont.no_dern_iter
AND rolpay.cd_role = 'pay'
AND rolpay.ind_pay_pri = '1'
LEFT JOIN
VIRAGE.role rolAutre
ON rolAutre.id_cont = cont.id_cont
AND rolAutre.no_iter_cont = cont.no_dern_iter
UNION
SELECT DISTINCT
CAST (tcm.con_sequence AS NUMBER (10, 0)) AS id_cont,
CAST (tcm.con_numero_contrat AS VARCHAR2 (20)) AS no_polc,
CAST (vd.cd_divs_compt AS VARCHAR2 (11)) AS cd_divs,
CAST (tcm.con_code_prodduit AS NUMBER (5, 0)) AS no_prod,
CAST (prod.cd_cie_encai AS VARCHAR2 (1)) AS cd_cie_encai,
CAST (prod.cd_faml_cptb AS VARCHAR2 (11)) AS cd_faml_cptb,
CAST (tcm.con_no_distributeur AS VARCHAR2 (15)) AS no_dist_init,
CAST (ctrpy.no_ctrpy AS NUMBER) AS no_intr_princ,
CAST (ctrpy.no_ctrpy AS NUMBER) AS no_intr_pay
FROM TPA.TPA_CONTRAT_MENSUEL tcm
INNER JOIN
VIRAGE.produit prod
ON prod.no_prod = tcm.con_code_prodduit
LEFT JOIN
counterparty ctrpy
ON ctrpy.last_name = tcm.con_nom_ass_princ
AND ctrpy.frst_name = tcm.con_prenom_ass_princ
AND ctrpy.dt_birth = tcm.con_date_naiss_ass_princ
INNER JOIN
v_distributeur vd
ON tcm.con_no_distributeur = vd.no_dist
WHERE TCM.CON_VERSION_CONTRAT=1
Indexes can only be created in tables.
Make sure you create an index for every single foreign key in every table. Oracle does not create them by default as other systems do.
Check also the performance of the sub-query and if it takes too long you should also create indexes for every attribute in the WHERE clause.
Don't forget that indexes need maintenance.
The scenerio
explain plan for
select l.etl_id , v.*
from v_load_base v, etl_log l
where l.is_active = 1
and v.ddate between trunc(l.load_from_date) and l.load_to_date
and v.starttime_full between l.load_from_date and l.load_to_date;
Produces this execution plan
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 444 | | 31624 (4)| 00:06:20 |
| 1 | SORT ORDER BY | | 3 | 444 | | 31624 (4)| 00:06:20 |
|* 2 | HASH JOIN | | 3 | 444 | | 31623 (4)| 00:06:20 |
| 3 | NESTED LOOPS OUTER | | 3 | 378 | | 31413 (4)| 00:06:17 |
|* 4 | HASH JOIN | | 3 | 348 | | 31410 (4)| 00:06:17 |
|* 5 | HASH JOIN | | 1252 | 118K| 2144K| 23428 (4)| 00:04:42 |
|* 6 | HASH JOIN | | 27786 | 1818K| | 764 (7)| 00:00:10 |
| 7 | NESTED LOOPS | | 8 | 264 | | 7 (0)| 00:00:01 |
|* 8 | TABLE ACCESS FULL | ETL_LOG | 1 | 21 | | 3 (0)| 00:00:01 |
|* 9 | TABLE ACCESS FULL | MD | 8 | 96 | | 4 (0)| 00:00:01 |
| 10 | TABLE ACCESS FULL | DS | 479K| 15M| | 748 (6)| 00:00:09 |
| 11 | TABLE ACCESS FULL | MDS | 7280K| 208M| | 7823 (5)| 00:01:34 |
| 12 | TABLE ACCESS FULL | TASKS | 7760K| 140M| | 7844 (5)| 00:01:35 |
| 13 | TABLE ACCESS BY INDEX ROWID| ETL_GIS | 1 | 10 | | 1 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | ETL_GIS_UK | 1 | | | 0 (0)| 00:00:01 |
| 15 | TABLE ACCESS FULL | DETAILS_TABLE | 292K| 6280K| | 204 (8)| 00:00:03 |
--------------------------------------------------------------------------------------------------------
The join predicate with the table etl_log was pushed down to the view v_load_base (line 8).
I created a view called v_load_base_active based on the same exact query as the one above.
Querying the new view produces the following plan
explain plan for select * from v_load_base_active;
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 861 | | 63583 (8)| 00:12:43 |
| 1 | NESTED LOOPS | | 3 | 861 | | 63583 (8)| 00:12:43 |
|* 2 | TABLE ACCESS FULL | ETL_LOG | 1 | 21 | | 3 (0)| 00:00:01 |
|* 3 | VIEW | V_LOAD_BASE | 3 | 798 | | 63580 (8)| 00:12:43 |
| 4 | SORT ORDER BY | | 422K| 51M| 110M| 63580 (8)| 00:12:43 |
|* 5 | HASH JOIN RIGHT OUTER | | 422K| 51M| | 51513 (9)| 00:10:19 |
| 6 | TABLE ACCESS FULL | ETL_GIS | 5958 | 59580 | | 17 (0)| 00:00:01 |
|* 7 | HASH JOIN | | 422K| 47M| 9712K| 51488 (9)| 00:10:18 |
| 8 | TABLE ACCESS FULL | LINES_DETAILS | 292K| 6280K| | 204 (8)| 00:00:03 |
|* 9 | HASH JOIN | | 422K| 38M| 35M| 48647 (10)| 00:09:44 |
|* 10 | HASH JOIN | | 422K| 30M| | 27365 (14)| 00:05:29 |
| 11 | TABLE ACCESS FULL | MD | 3103 | 37236 | | 4 (0)| 00:00:01 |
|* 12 | HASH JOIN | | 7301K| 445M| 21M| 24366 (3)| 00:04:53 |
| 13 | TABLE ACCESS FULL| DS | 479K| 15M| | 748 (6)| 00:00:09 |
| 14 | TABLE ACCESS FULL| MSD | 7280K| 208M| | 7823 (5)| 00:01:34 |
| 15 | TABLE ACCESS FULL | TASKS | 7760K| 140M| | 7844 (5)| 00:01:35 |
----------------------------------------------------------------------------------------------------
The predicate is not pushed. This leads to a major decrease in performance.
I've tried setting a hint explicitly in the view /*+ PUSH_PRED(v) */ but the plan does not change.
How can i make the optimizer push the predicate also within a view ... ?
v_load_base does not contain analytic functions. The first query proves that the predicate can be pushed.
EDIT
notice that oracle does not state in the execution plan that a predicate was pushed with VIEW PUSHED PREDICATE. but, looking at the plan it's clear that oracle transformed the view's sql to include the etl_log predicate.
I doubt that it was pushing predicate in the first case, because it would be in the plan. More likely it was merging which is controlled by MERGE/NO_MERGE hints. See example below.
With NO_MERGE:
SQL> explain plan for
2 select /*+NO_MERGE(so)*/ *
3 from siebel.s_org_ext soe,
4 (select sx.attrib_08, s.*
5 from siebel.s_opty s
6 inner join siebel.s_opty_x sx on s.row_id = sx.row_id) so
7 where soe.row_id = so.pr_dept_ou_id
8 and soe.row_id like '1-8ZT%'
9 and so.db_last_upd between soe.db_last_upd and soe.db_last_upd - 365;
Explained
SQL> select * from table(dbms_xplan.display);
Plan hash value: 1802470607
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13258 | 55 (2)| 00:00:01 |
|* 1 | HASH JOIN | | 1 | 13258 | 55 (2)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| S_ORG_EXT | 1 | 1047 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | S_ORG_EXT_P1 | 1 | | 2 (0)| 00:00:01 |
| 4 | VIEW | | 1084 | 12M| 52 (2)| 00:00:01 |
|* 5 | HASH JOIN | | 1084 | 528K| 52 (2)| 00:00:01 |
| 6 | TABLE ACCESS FULL | S_OPTY_X | 1573 | 15730 | 17 (0)| 00:00:01 |
|* 7 | TABLE ACCESS FULL | S_OPTY | 1084 | 517K| 34 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
With MERGE:
SQL> explain plan for
2 select /*+MERGE(so)*/*
3 from siebel.s_org_ext soe,
4 (select sx.attrib_08, s.*
5 from siebel.s_opty s
6 inner join siebel.s_opty_x sx on s.row_id = sx.row_id) so
7 where soe.row_id = so.pr_dept_ou_id
8 and soe.row_id like '1-8ZT%'
9 and so.db_last_upd between soe.db_last_upd and soe.db_last_upd - 365;
Explained
SQL> select * from table(dbms_xplan.display);
Plan hash value: 4111959163
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1546 | 6 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 1546 | 6 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 1536 | 5 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| S_ORG_EXT | 1 | 1047 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | S_ORG_EXT_P1 | 1 | | 2 (0)| 00:00:01 |
|* 5 | TABLE ACCESS BY INDEX ROWID| S_OPTY | 1 | 489 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | S_OPTY_M64_X | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | S_OPTY_X | 1 | 10 | 1 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | S_OPTY_X_P1 | 1 | | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
So try to force optimizer use merging with you view and see if plan changes.
I have a view where if I select like this:
select * from view where date = '17-sep-10'
it returns in seconds.
If I use a dynamic date:
select *
from view
where date = to_date((select current_business_date
from v_business_day),
'mm/dd/yyyy')
it returns in 20 mins.
Why would hard coding improve performance so much? Also, the select in the to_date is not the issue (I think). It returns almost instanteously when running it.
Here is the desc for the view:
JAID_OWNER#algoja1p> desc v_positions_rm_base
Name Null? Type
----------------------------------------- -------- ----------------------------
RUN_KEY NOT NULL NUMBER(10)
POSITION_KEY NOT NULL NUMBER(10)
POSITIONS VARCHAR2(50)
INSTRUMENT_ID VARCHAR2(151)
BUSINESS_DATE NOT NULL DATE
PROCESSING_DATE DATE
PROCESSING_STATUS_KEY NOT NULL NUMBER(10)
Here is the explain plan for when I hardcode the date. I changed the query to do a to_date on a hardcoded value so it's consistent..
explain plan for select * from v_positions_rm_base where business_date = to_date('09/17/2010', 'mm/dd/yyyy')
-----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 518 | 1003K| 1679 (2)| 00:00:21 |
|* 1 | FILTER | | | | | |
|* 2 | FILTER | | | | | |
|* 3 | HASH JOIN RIGHT OUTER | | 10360 | 19M| 1651 (2)| 00:00:20 |
| 4 | INDEX FAST FULL SCAN | RM_SRC_ACCT_UDX | 601 | 7212 | 2 (0)| 00:00:01 |
| 5 | VIEW | | 10360 | 19M| 1648 (2)| 00:00:20 |
|* 6 | HASH JOIN RIGHT OUTER | | 10360 | 20M| 1648 (2)| 00:00:20 |
| 7 | VIEW | V_RM_FUTURES_CODE_TRANS_FLAT | 1 | 96 | 9 (12)| 00:00:01 |
| 8 | HASH GROUP BY | | 1 | 51 | 9 (12)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 3 | 153 | 8 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | CODE_TRANSLATION_IDX3 | 3 | | 7 (0)| 00:00:01 |
|* 11 | HASH JOIN RIGHT OUTER | | 10360 | 19M| 1638 (2)| 00:00:20 |
| 12 | VIEW | V_RM_FUTURES_CODE_TRANS_FLAT | 1 | 96 | 9 (12)| 00:00:01 |
| 13 | HASH GROUP BY | | 1 | 51 | 9 (12)| 00:00:01 |
| 14 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 3 | 153 | 8 (0)| 00:00:01 |
|* 15 | INDEX RANGE SCAN | CODE_TRANSLATION_IDX3 | 3 | | 7 (0)| 00:00:01 |
|* 16 | HASH JOIN RIGHT OUTER | | 10360 | 18M| 1629 (2)| 00:00:20 |
| 17 | VIEW | V_RM_FUTURES_CODE_TRANS_FLAT | 404 | 42420 | 12 (9)| 00:00:01 |
| 18 | HASH GROUP BY | | 404 | 20604 | 12 (9)| 00:00:01 |
| 19 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 404 | 20604 | 11 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 404 | | 3 (0)| 00:00:01 |
|* 21 | HASH JOIN RIGHT OUTER | | 10360 | 17M| 1616 (2)| 00:00:20 |
| 22 | VIEW | V_RM_FUTURES_CODE_TRANS_FLAT | 404 | 42420 | 12 (9)| 00:00:01 |
| 23 | HASH GROUP BY | | 404 | 20604 | 12 (9)| 00:00:01 |
| 24 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 404 | 20604 | 11 (0)| 00:00:01 |
|* 25 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 404 | | 3 (0)| 00:00:01 |
|* 26 | HASH JOIN RIGHT OUTER | | 10360 | 16M| 1603 (2)| 00:00:20 |
| 27 | TABLE ACCESS FULL | SOURCE_SYSTEM | 68 | 748 | 3 (0)| 00:00:01 |
|* 28 | HASH JOIN RIGHT OUTER | | 10360 | 16M| 1599 (2)| 00:00:20 |
| 29 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 1 | 51 | 2 (0)| 00:00:01 |
|* 30 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 1 | | 1 (0)| 00:00:01 |
| 31 | VIEW | | 10360 | 16M| 1597 (2)| 00:00:20 |
|* 32 | HASH JOIN RIGHT OUTER | | 10360 | 7527K| 1597 (2)| 00:00:20 |
| 33 | TABLE ACCESS BY INDEX ROWID | PARAMETER_CONTROL | 1 | 38 | 2 (0)| 00:00:01 |
|* 34 | INDEX RANGE SCAN | PARAMETER_CONTROL_IDX3 | 1 | | 1 (0)| 00:00:01 |
|* 35 | HASH JOIN RIGHT OUTER | | 10360 | 7142K| 1594 (2)| 00:00:20 |
| 36 | VIEW | V_ENTITY_FLAT | 1742 | 282K| 35 (9)| 00:00:01 |
|* 37 | HASH JOIN RIGHT OUTER | | 1742 | 229K| 35 (9)| 00:00:01 |
| 38 | INDEX FAST FULL SCAN | ENTITY_IDX_5 | 1742 | 40066 | 6 (0)| 00:00:01 |
|* 39 | HASH JOIN RIGHT OUTER | | 1742 | 190K| 28 (8)| 00:00:01 |
| 40 | INDEX FAST FULL SCAN | ENTITY_IDX_5 | 1742 | 47034 | 6 (0)| 00:00:01 |
|* 41 | HASH JOIN RIGHT OUTER | | 1742 | 144K| 21 (5)| 00:00:01 |
| 42 | INDEX FAST FULL SCAN | ENTITY_IDX_5 | 1742 | 47034 | 6 (0)| 00:00:01 |
|* 43 | HASH JOIN RIGHT OUTER | | 1742 | 98K| 15 (7)| 00:00:01 |
| 44 | INDEX FAST FULL SCAN | ENTITY_IDX_5 | 1742 | 47034 | 6 (0)| 00:00:01 |
| 45 | TABLE ACCESS FULL | ENTITY | 1742 | 54002 | 8 (0)| 00:00:01 |
|* 46 | HASH JOIN RIGHT OUTER | | 2432 | 1282K| 1559 (1)| 00:00:19 |
| 47 | TABLE ACCESS FULL | INSTRUMENT_ID_TYPE | 8 | 88 | 3 (0)| 00:00:01 |
|* 48 | HASH JOIN RIGHT OUTER | | 2432 | 1256K| 1555 (1)| 00:00:19 |
| 49 | TABLE ACCESS BY INDEX ROWID | PROCESSING_STATUS | 1 | 76 | 1 (0)| 00:00:01 |
|* 50 | INDEX UNIQUE SCAN | PROCESSING_STATUS_PK | 1 | | 0 (0)| 00:00:01 |
|* 51 | HASH JOIN RIGHT OUTER | | 2432 | 1075K| 1554 (1)| 00:00:19 |
|* 52 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 1 | 65 | 2 (0)| 00:00:01 |
|* 53 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 1 | | 1 (0)| 00:00:01 |
|* 54 | HASH JOIN RIGHT OUTER | | 2432 | 921K| 1551 (1)| 00:00:19 |
|* 55 | TABLE ACCESS BY INDEX ROWID| CODE_TRANSLATION | 1 | 65 | 2 (0)| 00:00:01 |
|* 56 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 1 | | 1 (0)| 00:00:01 |
|* 57 | TABLE ACCESS BY INDEX ROWID| POSITIONS | 2432 | 767K| 1549 (1)| 00:00:19 |
|* 58 | INDEX RANGE SCAN | POSITIONS_IDX_01 | 5676 | | 737 (2)| 00:00:09 |
|* 59 | INDEX RANGE SCAN | PARAMETER_CONTROL_IDX3 | 1 | 27 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------------
and here is the explain plan for the other view:
explain plan for select * from v_positions_rm_base where business_date = to_date((select current_business_date from v_business_day), 'mm/dd/yyyy');
-------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 171K| 324M| 366K (3)| 01:13:16 |
|* 1 | FILTER | | | | | |
|* 2 | FILTER | | | | | |
|* 3 | HASH JOIN RIGHT OUTER | | 3436K| 6485M| 366K (3)| 01:13:16 |
| 4 | INDEX FAST FULL SCAN | RM_SRC_ACCT_UDX | 601 | 7212 | 2 (0)| 00:00:01 |
|* 5 | VIEW | | 3436K| 6446M| 366K (3)| 01:13:15 |
|* 6 | HASH JOIN RIGHT OUTER | | 3436K| 6806M| 366K (3)| 01:13:15 |
| 7 | VIEW | V_RM_FUTURES_CODE_TRANS_FLAT | 1 | 96 | 9 (12)| 00:00:01 |
| 8 | HASH GROUP BY | | 1 | 51 | 9 (12)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 3 | 153 | 8 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | CODE_TRANSLATION_IDX3 | 3 | | 7 (0)| 00:00:01 |
|* 11 | HASH JOIN RIGHT OUTER | | 3436K| 6492M| 366K (3)| 01:13:15 |
| 12 | VIEW | V_RM_FUTURES_CODE_TRANS_FLAT | 1 | 96 | 9 (12)| 00:00:01 |
| 13 | HASH GROUP BY | | 1 | 51 | 9 (12)| 00:00:01 |
| 14 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 3 | 153 | 8 (0)| 00:00:01 |
|* 15 | INDEX RANGE SCAN | CODE_TRANSLATION_IDX3 | 3 | | 7 (0)| 00:00:01 |
|* 16 | HASH JOIN RIGHT OUTER | | 3436K| 6177M| 366K (3)| 01:13:14 |
| 17 | VIEW | V_RM_FUTURES_CODE_TRANS_FLAT | 404 | 42420 | 12 (9)| 00:00:01 |
| 18 | HASH GROUP BY | | 404 | 20604 | 12 (9)| 00:00:01 |
| 19 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 404 | 20604 | 11 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 404 | | 3 (0)| 00:00:01 |
|* 21 | HASH JOIN RIGHT OUTER | | 3436K| 5833M| 366K (3)| 01:13:13 |
| 22 | VIEW | V_RM_FUTURES_CODE_TRANS_FLAT | 404 | 42420 | 12 (9)| 00:00:01 |
| 23 | HASH GROUP BY | | 404 | 20604 | 12 (9)| 00:00:01 |
| 24 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 404 | 20604 | 11 (0)| 00:00:01 |
|* 25 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 404 | | 3 (0)| 00:00:01 |
|* 26 | HASH JOIN RIGHT OUTER | | 3436K| 5489M| 366K (3)| 01:13:13 |
| 27 | TABLE ACCESS FULL | SOURCE_SYSTEM | 68 | 748 | 3 (0)| 00:00:01 |
|* 28 | HASH JOIN RIGHT OUTER | | 3436K| 5453M| 365K (3)| 01:13:12 |
| 29 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 1 | 51 | 2 (0)| 00:00:01 |
|* 30 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 1 | | 1 (0)| 00:00:01 |
| 31 | VIEW | | 3436K| 5286M| 365K (3)| 01:13:11 |
|* 32 | HASH JOIN RIGHT OUTER | | 3436K| 2438M| 365K (3)| 01:13:11 |
| 33 | TABLE ACCESS BY INDEX ROWID | PARAMETER_CONTROL | 1 | 38 | 2 (0)| 00:00:01 |
|* 34 | INDEX RANGE SCAN | PARAMETER_CONTROL_IDX3 | 1 | | 1 (0)| 00:00:01 |
| 35 | MERGE JOIN OUTER | | 3436K| 2313M| 365K (3)| 01:13:11 |
| 36 | MERGE JOIN OUTER | | 3436K| 2064M| 365K (3)| 01:13:11 |
| 37 | SORT JOIN | | 806K| 357M| 365K (3)| 01:13:10 |
| 38 | MERGE JOIN OUTER | | 806K| 357M| 365K (3)| 01:13:10 |
| 39 | SORT JOIN | | 806K| 348M| 365K (3)| 01:13:10 |
|* 40 | HASH JOIN RIGHT OUTER | | 806K| 348M| 365K (3)| 01:13:10 |
|* 41 | TABLE ACCESS BY INDEX ROWID | CODE_TRANSLATION | 1 | 65 | 2 (0)| 00:00:01 |
|* 42 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 1 | | 1 (0)| 00:00:01 |
|* 43 | HASH JOIN RIGHT OUTER | | 806K| 298M| 365K (3)| 01:13:10 |
|* 44 | TABLE ACCESS BY INDEX ROWID| CODE_TRANSLATION | 1 | 65 | 2 (0)| 00:00:01 |
|* 45 | INDEX RANGE SCAN | CODE_TRANS_TYPE_IDX | 1 | | 1 (0)| 00:00:01 |
|* 46 | TABLE ACCESS FULL | POSITIONS | 806K| 248M| 365K (3)| 01:13:09 |
|* 47 | SORT JOIN | | 8 | 88 | 4 (25)| 00:00:01 |
| 48 | TABLE ACCESS FULL | INSTRUMENT_ID_TYPE | 8 | 88 | 3 (0)| 00:00:01 |
|* 49 | SORT JOIN | | 1742 | 282K| 36 (12)| 00:00:01 |
| 50 | VIEW | V_ENTITY_FLAT | 1742 | 282K| 35 (9)| 00:00:01 |
|* 51 | HASH JOIN RIGHT OUTER | | 1742 | 229K| 35 (9)| 00:00:01 |
| 52 | INDEX FAST FULL SCAN | ENTITY_IDX_5 | 1742 | 40066 | 6 (0)| 00:00:01 |
|* 53 | HASH JOIN RIGHT OUTER | | 1742 | 190K| 28 (8)| 00:00:01 |
| 54 | INDEX FAST FULL SCAN | ENTITY_IDX_5 | 1742 | 47034 | 6 (0)| 00:00:01 |
|* 55 | HASH JOIN RIGHT OUTER | | 1742 | 144K| 21 (5)| 00:00:01 |
| 56 | INDEX FAST FULL SCAN | ENTITY_IDX_5 | 1742 | 47034 | 6 (0)| 00:00:01 |
|* 57 | HASH JOIN RIGHT OUTER | | 1742 | 98K| 15 (7)| 00:00:01 |
| 58 | INDEX FAST FULL SCAN | ENTITY_IDX_5 | 1742 | 47034 | 6 (0)| 00:00:01 |
| 59 | TABLE ACCESS FULL | ENTITY | 1742 | 54002 | 8 (0)| 00:00:01 |
|* 60 | SORT JOIN | | 1 | 76 | 2 (50)| 00:00:01 |
| 61 | TABLE ACCESS BY INDEX ROWID | PROCESSING_STATUS | 1 | 76 | 1 (0)| 00:00:01 |
|* 62 | INDEX UNIQUE SCAN | PROCESSING_STATUS_PK | 1 | | 0 (0)| 00:00:01 |
| 63 | MERGE JOIN CARTESIAN | | 1 | 119 | 4 (0)| 00:00:01 |
| 64 | MERGE JOIN CARTESIAN | | 1 | 81 | 3 (0)| 00:00:01 |
| 65 | MERGE JOIN CARTESIAN | | 1 | 54 | 2 (0)| 00:00:01 |
|* 66 | INDEX RANGE SCAN | PARAMETER_CONTROL_IDX3 | 1 | 27 | 1 (0)| 00:00:01 |
| 67 | BUFFER SORT | | 1 | 27 | 1 (0)| 00:00:01 |
|* 68 | INDEX RANGE SCAN | PARAMETER_CONTROL_IDX3 | 1 | 27 | 1 (0)| 00:00:01 |
| 69 | BUFFER SORT | | 1 | 27 | 2 (0)| 00:00:01 |
|* 70 | INDEX RANGE SCAN | PARAMETER_CONTROL_IDX3 | 1 | 27 | 1 (0)| 00:00:01 |
| 71 | BUFFER SORT | | 1 | 38 | 3 (0)| 00:00:01 |
|* 72 | TABLE ACCESS BY INDEX ROWID | PARAMETER_CONTROL | 1 | 38 | 1 (0)| 00:00:01 |
|* 73 | INDEX RANGE SCAN | PARAMETER_CONTROL_IDX1 | 2 | | 0 (0)| 00:00:01 |
|* 74 | INDEX RANGE SCAN | PARAMETER_CONTROL_IDX3 | 1 | 27 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------------------------
You have two queries
select * from view where date = '17-sep-10'
select * from view where date = to_date(...
In the first, the 'date' column in the view is being compared to a character literal. In the second it is being compared to a date.
If the first is working (and quickly), it is possible that the 'date' column in the view is a VARCHAR2 column rather than a date. The fact that you are doing a TO_DATE on a column called current_business_date suggests that you may be using the wrong datatypes.
Do a DESC VIEW in SQL*Plus (or equivalent in whatever tool you use).
Also do an EXPLAIN PLAN for both
select * from view where date = '17-sep-10'
and
select * from view where date = date '2010-09-17'
Response to Cagcowboy
There is no issue with the to_date on the other side of the = from the column.
Only casting a COLUMN away from type is an issue.
Example:
create table index_test
as
select object_name, created as create_dt from all_objects;
create index it_create_dt_idx on index_test (create_dt) compute statistics;
INDEX is used with no issue with TO_DATE is NOT on the Column
set autotrace on explain
select * from index_test where create_dt = to_date('17-SEP-2000', 'DD-MON-YYYY');
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=1 Card=1 Bytes=26)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'INDEX_TEST' (TABLE) (Cos
t=1 Card=1 Bytes=26)
2 1 INDEX (RANGE SCAN) OF 'IT_CREATE_DT_IDX' (INDEX) (Cost=1
Card=1)
A function on THE INDEXED COLUMN is obviates the index.
SQL> select * from index_test where trunc(create_dt) = to_date('17-SEP-2000', 'DD-MON-YYYY');
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=59 Card=3 Bytes=78
)
1 0 TABLE ACCESS (FULL) OF 'INDEX_TEST' (TABLE) (Cost=59 Card=
3 Bytes=78)
I'm going to stick my head out and put this down to column stats or skew.
One plan has
|* 57 | TABLE ACCESS BY INDEX ROWID| POSITIONS | 2432 | 767K| 1549 (1)| 00:00:19 |
|* 58 | INDEX RANGE SCAN | POSITIONS_IDX_01 | 5676 | | 737 (2)| 00:00:09 |
The other has
|* 46 | TABLE ACCESS FULL | POSITIONS | 806K| 248M| 365K (3)| 01:13:09 |
Given the date '17-Sep-2010', Oracle is assuming several thousand rows will be returned. Given another non-specific date, Oracle is assuming a much larger number, so large that the date index is useless. I suspect most of the rows in the table were for the same small number of dates (probably less than a hundred distinct values - but you can look in NUM_DISTINCT in USER_TAB_COLUMNS).
I say were because I think the stats may be out of date. There'll be a LOW_VALUE and HIGH_VALUE on USER_TAB_COLUMNS for that date column in the table (in RAW format, not as actual dates). When faced with a query for a value above the recorded high_value, 10g makes some assumptions. If there are a million rows for a hundred distinct values, it will assume 10,000 rows for each value [in the absence of histograms] but for a value above the HIGH_VALUE it will assume less than 10,000 rows. It gets all statistical in its calculations, so its hard to be precise. But its enough that the database is thinking that rows for Sept 17th are sufficiently small in number as to make it worth using the index.
So there's four things to determine.
How many rows are in the table, and what is the distribution over dates.
How many rows do the stats indicate are in the table and what do the stats suggest is the distribution over dates.
On the execution plans, it would also be helpful to know on which step the date predicate was being applied.
The actual response time culprit in the second plan is the full scan on POSITIONS. In the first plan we are doing an index range scan using POSITIONS_IDX_01. What columns are in that index? In particular, do any of them relate to the business_date column in the view?
I'm guessing that the v_business_day view is based on PARAMETER_CONTROL, since that seems to be referenced more times in the second plan than in the first. The portions of the second plan that are based entirely on this table have estimated cardinalities of 1, so it does not appear that the problem is that Oracle thinks the subquery might be returning multiple rows (which jives with your statement that adding the condition on ROWNUM to the subquery did not change the performance).
Response to comment: It sounds like the statistics on POSITIONS.BUSINESS_DATE are such that the optimizer can see that the literal date value will be highly selective, but that an arbitrary date value is likely to be highly unselective. You should look into the statistics -- in USER_TABLES, USER_INDEXES, and USER_HISTOGRAMS -- to see if they are out of date and what they indicate about the data distribution of this column.
The simplest way out of this may be to do one query to get the current business date, then insert it as a literal into the query against the complex view.