How do I improve the following SQL that has self-join - sql

After doing a select, I am doing a self-join and a distinct on the data. I am not sure if there is a better way to write this query. Could you suggest?
Below is the Query, and the explain plan output.
WITH data
AS ( SELECT san.S1FK_C_ID,
san.S1FK_CF_ID,
san.S1FK_A_ID,
san.S1FK_A_TYPE,
san.S1FK_S_TYPE,
san.S1FK_B_FUNC,
AU.AS1FK_A_ID,
AU.AS1FK_B_FUNC,
AU.AS1FK_S_TYPE,
AU.AS1FK_T_CODE,
A2FK_B_ID,
A2FK_NBR,
A2FK_C_CD,
A1FK_B_ID,
A1FK_NBR,
A1FK_C_CD,
AU.R_NAME,
IND
FROM N_RULE cnr,
SAN san,
ACCT_USG AU
WHERE AU.R_NAME = CNR.R_NAME
AND AU.A2FK_C_CD = CNR.C_CD
AND AU.AS1FK_B_FUNC = CNR.B_FUNC
AND AU.AS1FK_A_ID = san.AS1FK_ID || ''
AND AU.AS1FK_B_FUNC = san.AS1FK_B_FUNC
AND AU.AS1FK_S_TYPE = san.AS1FK_S_TYPE
AND AU.AS1FK_T_CODE = san.AS1FK_A_TYPE
AND CNR.FM_CODE = 'SP'
AND san.STATUS = 'A'
AND san.AS1FK_B_FUNC = CNR.B_FUNC
ORDER BY AU.AS1FK_A_ID)
SELECT DISTINCT A.A2FK_C_CD AS C_CD,
-- secondary id's
B.S1FK_C_ID AS C_ID_2,
B.S1FK_CF_ID AS CF_ID_2,
B.S1FK_A_ID AS A_ID_2,
B.S1FK_B_FUNC AS B_FUNC_2,
B.S1FK_S_TYPE AS S_TYPE_2,
B.S1FK_A_TYPE AS A_TYPE_2,
--primary id's
A.S1FK_A_ID AS A_ID_1,
A.S1FK_B_FUNC AS B_FUNC_1,
A.S1FK_S_TYPE AS S_TYPE_1,
A.S1FK_A_TYPE AS A_TYPE_1
FROM data A, --A is the set of primary and standalone id's
data B
--B is the primary and secondary id's
WHERE
B .R_NAME = A.R_NAME
--as join
AND B.AS1FK_B_FUNC = A.AS1FK_B_FUNC
AND B.AS1FK_S_TYPE = A.AS1FK_S_TYPE
AND B.AS1FK_T_CODE = A.AS1FK_T_CODE
--accts join
AND B.A2FK_NBR = A.A2FK_NBR
AND B.A2FK_B_ID = A.A2FK_B_ID
AND B.A2FK_C_CD = A.A2FK_C_CD
AND B.A1FK_NBR = A.A1FK_NBR
AND B.A1FK_B_ID = A.A1FK_B_ID
AND B.A1FK_C_CD = A.A1FK_C_CD
--s fk join
AND B.S1FK_C_ID = A.S1FK_C_ID
AND B.S1FK_CF_ID = A.S1FK_CF_ID
AND B.S1FK_S_TYPE = A.S1FK_S_TYPE
AND B.S1FK_B_FUNC = A.S1FK_B_FUNC
AND B.S1FK_A_TYPE = A.S1FK_A_TYPE
AND ( --join secondary ( N ) and primary id's ( Y ) to primary id's
( 'Y' = A.IND
AND B.IND IN ('N', 'Y') )
OR --join standalone ( ' ' ) id's to themselves
( ' ' = B.IND
AND ' ' = A.IND )
AND B.AS1FK_A_ID = A.AS1FK_A_ID
);
Plan:
PLAN_TABLE_OUTPUT
Plan hash value: 3120521488
----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 450 | 18 (17)| 00:00:01 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D949F_E879D9BC | | | | |
| 3 | SORT ORDER BY | | 1 | 296 | 12 (9)| 00:00:01 |
| 4 | NESTED LOOPS | | 1 | 296 | 11 (0)| 00:00:01 |
| 5 | NESTED LOOPS | | 7412 | 1889K| 11 (0)| 00:00:01 |
|* 6 | TABLE ACCESS FULL | SAN | 255 | 20910 | 11 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| ACCT_USG | 29 | 5191 | 0 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | ACCT_USG_PK | 1 | | 0 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | N_RULE_PK | 1 | 35 | 0 (0)| 00:00:01 |
| 10 | HASH UNIQUE | | 1 | 450 | 6 (34)| 00:00:01 |
|* 11 | HASH JOIN | | 1 | 450 | 5 (20)| 00:00:01 |
| 12 | VIEW | | 1 | 225 | 2 (0)| 00:00:01 |
| 13 | TABLE ACCESS FULL | SYS_TEMP_0FD9D949F_E879D9BC | 1 | 225 | 2 (0)| 00:00:01 |
| 14 | VIEW | | 1 | 225 | 2 (0)| 00:00:01 |
| 15 | TABLE ACCESS FULL | SYS_TEMP_0FD9D949F_E879D9BC | 1 | 225 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - filter("SAN"."EFF_STATUS_CODE"='A')
8 - access("AU"."AS1FK_A_ID"="SAN"."AS1FK_ID"||'' AND
"AU"."AS1FK_T_CODE"="SAN"."AS1FK_A_TYPE" AND
"AU"."AS1FK_S_TYPE"="SAN"."AS1FK_S_TYPE" AND
"AU"."AS1FK_B_FUNC"="SAN"."AS1FK_B_FUNC")
9 - access("CNR"."FM_CODE"='SP' AND "SAN"."S1FK_C_ID"="CNR"."CLRG_ORG_ID" AND
"SAN"."AS1FK_B_FUNC"="CNR"."B_F_CODE" AND "AU"."A2FK_C_CD"="CNR"."C_CD" AND
"AU"."R_NAME"="CNR"."R_NAME")
filter("AU"."AS1FK_B_FUNC"="CNR"."B_F_CODE")
11 - access("B"."R_NAME"="A"."R_NAME" AND "B"."AS1FK_B_FUNC"="A"."AS1FK_B_FUNC" AND
"B"."AS1FK_S_TYPE"="A"."AS1FK_S_TYPE" AND "B"."AS1FK_T_CODE"="A"."AS1FK_T_CODE"
AND "B"."A2FK_NBR"="A"."A2FK_NBR" AND "B"."A2FK_B_ID"="A"."A2FK_B_ID" AND
"B"."A2FK_C_CD"="A"."A2FK_C_CD" AND "B"."A1FK_NBR"="A"."A1FK_NBR" AND
"B"."A1FK_B_ID"="A"."A1FK_B_ID" AND "B"."A1FK_C_CD"="A"."A1FK_C_CD" AND
"B"."S1FK_C_ID"="A"."S1FK_C_ID" AND "B"."S1FK_CF_ID"="A"."S1FK_CF_ID" AND
"B"."S1FK_S_TYPE"="A"."S1FK_S_TYPE" AND "B"."S1FK_B_FUNC"="A"."S1FK_B_FUNC" AND
"B"."STACO1FK_A_TYPE"="A"."STACO1FK_A_TYPE")
filter("A"."IND"='Y' AND ("B"."IND"='N' OR
"B"."IND"="A"."IND") OR "B"."IND"=' ' AND
"A"."IND"=' ' AND "B"."AS1FK_A_ID"="A"."AS1FK_A_ID" AND
"B"."IND"="A"."IND")
EDIT
~~~~
I edited the above SQL to remove self-joins and unnecessary group-by.
I am doing grouping only on primary_secondary rows based on join.
Between primary and secondary, I am deciding the primary acct that should be plugged in for secondary.
This is giving the same result. I am wondering if this can be further improved.
WITH data
AS ( SELECT sanw.STAC01FK_C_ID,
sanw.STAC01FK_CF_ID,
sanw.STAC01FK_A_ID,
sanw.STACO1FK_A_TYPE,
sanw.STAC01FK_S_TYPE,
sanw.STAC01FK_B_FUNC,
BAU.ASAC01FK_A_ID,
BAU.ASAC01FK_B_FUNC,
BAU.ASAC01FK_S_TYPE,
BAU.ASAC01FK_TYPE_CODE,
BAAC02FK_BANK_ID,
BAAC02FK_NBR,
BAAC02FK_CURR_CD,
BAAC01FK_BANK_ID,
BAAC01FK_NBR,
BAAC01FK_CURR_CD,
BAU.R_NAME,
PRIMARY_ACCT_IND
FROM N_RULE cnr,
SAN sanw,
ACCT_USG bau
WHERE BAU.R_NAME = CNR.R_NAME
AND BAU.BAAC02FK_CURR_CD = CNR.C_CD
AND BAU.ASAC01FK_B_FUNC = CNR.B_FUNC_CD
AND BAU.ASAC01FK_A_ID = sanw.ASAC01FK_ID
AND BAU.ASAC01FK_B_FUNC = sanw.ASAC01FK_B_FUNC
AND BAU.ASAC01FK_S_TYPE = sanw.ASAC01FK_S_TYPE
AND BAU.ASAC01FK_TYPE_CODE = sanw.ASAC01FK_A_TYPE
AND CNR.FM_CODE = 'SP'
AND sanw.EFF_STATUS_CODE = 'A'
AND sanw.ASAC01FK_B_FUNC = CNR.B_FUNC_CD),
primary_secondary
AS (SELECT PRIMARY_ACCT_IND,
B.BAAC02FK_CURR_CD AS C_CD,
B.STAC01FK_C_ID AS C_ID_2,
B.STAC01FK_CF_ID AS CF_ID_2,
-- secondary accounts
B.STAC01FK_A_ID AS A_ID_2,
B.STAC01FK_B_FUNC AS B_FUNC_2,
B.STAC01FK_S_TYPE AS S_TYPE_2,
B.STACO1FK_A_TYPE AS A_TYPE_2,
--primary accounts
B.STAC01FK_A_ID AS A_ID_1,
B.STAC01FK_B_FUNC AS B_FUNC_1,
B.STAC01FK_S_TYPE AS S_TYPE_1,
B.STACO1FK_A_TYPE AS A_TYPE_1,
RANK ()
OVER (
PARTITION BY
--bank acct join
B.BAAC02FK_CURR_CD,
--sa join
B.STAC01FK_S_TYPE,
B.STAC01FK_B_FUNC,
B.STACO1FK_A_TYPE,
B.STAC01FK_C_ID,
B.STAC01FK_CF_ID
ORDER BY
PRIMARY_ACCT_IND DESC)
AS d_rank
FROM data B
WHERE B.PRIMARY_ACCT_IND IN ('Y', 'N')),
stand_alone
AS (SELECT B.BAAC02FK_CURR_CD AS C_CD,
B.STAC01FK_C_ID AS C_ID_2,
B.STAC01FK_CF_ID AS CF_ID_2,
-- secondary accounts
B.STAC01FK_A_ID AS A_ID_2,
B.STAC01FK_B_FUNC AS B_FUNC_2,
B.STAC01FK_S_TYPE AS S_TYPE_2,
B.STACO1FK_A_TYPE AS A_TYPE_2,
--primary accounts
B.STAC01FK_A_ID AS A_ID_1,
B.STAC01FK_B_FUNC AS B_FUNC_1,
B.STAC01FK_S_TYPE AS S_TYPE_1,
B.STACO1FK_A_TYPE AS A_TYPE_1
FROM data B
WHERE B.PRIMARY_ACCT_IND = ' '),
PRIMARY
AS (SELECT C_CD,
C_ID_2,
CF_ID_2,
-- secondary accounts
A_ID_2,
B_FUNC_2,
S_TYPE_2,
A_TYPE_2,
--primary accounts
A_ID_1,
B_FUNC_1,
S_TYPE_1,
A_TYPE_1
FROM primary_secondary
WHERE D_RANK = 1),
SECONDARY
AS (SELECT ps.C_CD,
ps.C_ID_2,
ps.CF_ID_2,
-- secondary accounts
ps.A_ID_2,
ps.B_FUNC_2,
ps.S_TYPE_2,
ps.A_TYPE_2,
--primary accounts
p.A_ID_1,
p.B_FUNC_1,
p.S_TYPE_1,
p.A_TYPE_1
FROM primary_secondary ps, primary p
WHERE ps.D_RANK <> 1
AND ps.C_CD = p.C_CD
AND ps.C_ID_2 = p.C_ID_2
AND ps.CF_ID_2 = p.CF_ID_2
-- secondarary accounts
AND ps.B_FUNC_2 = p.B_FUNC_2
AND ps.S_TYPE_2 = p.S_TYPE_2
AND ps.A_TYPE_2 = p.A_TYPE_2)
SELECT * FROM secondary
UNION ALL
SELECT * FROM primary
UNION ALL
SELECT * FROM stand_alone
PLAN:
Plan hash value: 3159296610
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 33 | 3421 | 9 (56)| 00:00:01 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9DBAF1_9261CF31 | | | | |
|* 3 | HASH JOIN | | 11 | 3058 | 119 (1)| 00:00:02 |
|* 4 | HASH JOIN | | 96 | 18816 | 104 (1)| 00:00:02 |
|* 5 | INDEX RANGE SCAN | CNR_PK | 61 | 1769 | 1 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL | ACCT_USG | 8244 | 1344K| 102 (0)| 00:00:02 |
|* 7 | TABLE ACCESS FULL | SAN | 1444 | 115K| 15 (0)| 00:00:01 |
| 8 | LOAD AS SELECT | SYS_TEMP_0FD9DBAF2_9261CF31 | | | | |
| 9 | WINDOW SORT | | 11 | 594 | 3 (34)| 00:00:01 |
|* 10 | VIEW | | 11 | 594 | 2 (0)| 00:00:01 |
| 11 | TABLE ACCESS FULL | SYS_TEMP_0FD9DBAF1_9261CF31 | 11 | 2343 | 2 (0)| 00:00:01 |
| 12 | LOAD AS SELECT | SYS_TEMP_0FD9DBAF3_9261CF31 | | | | |
|* 13 | VIEW | | 11 | 1089 | 2 (0)| 00:00:01 |
| 14 | TABLE ACCESS FULL | SYS_TEMP_0FD9DBAF2_9261CF31 | 11 | 682 | 2 (0)| 00:00:01 |
| 15 | UNION-ALL | | | | | |
|* 16 | HASH JOIN | | 11 | 1672 | 5 (20)| 00:00:01 |
|* 17 | VIEW | | 11 | 792 | 2 (0)| 00:00:01 |
| 18 | TABLE ACCESS FULL | SYS_TEMP_0FD9DBAF2_9261CF31 | 11 | 682 | 2 (0)| 00:00:01 |
| 19 | VIEW | | 11 | 880 | 2 (0)| 00:00:01 |
| 20 | TABLE ACCESS FULL | SYS_TEMP_0FD9DBAF3_9261CF31 | 11 | 946 | 2 (0)| 00:00:01 |
| 21 | VIEW | | 11 | 1067 | 2 (0)| 00:00:01 |
| 22 | TABLE ACCESS FULL | SYS_TEMP_0FD9DBAF3_9261CF31 | 11 | 946 | 2 (0)| 00:00:01 |
|* 23 | VIEW | | 11 | 682 | 2 (0)| 00:00:01 |
| 24 | TABLE ACCESS FULL | SYS_TEMP_0FD9DBAF1_9261CF31 | 11 | 2343 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("BAU"."ASAC01FK_A_ID"="SANW"."ASAC01FK_ID"||'' AND
"BAU"."ASAC01FK_B_FUNC"="SANW"."ASAC01FK_B_FUNC" AND
"BAU"."ASAC01FK_S_TYPE"="SANW"."ASAC01FK_S_TYPE" AND
"BAU"."ASAC01FK_TYPE_CODE"="SANW"."ASAC01FK_A_TYPE" AND
"SANW"."ASAC01FK_B_FUNC"="CNR"."B_FUNC_CD")
4 - access("BAU"."R_NAME"="CNR"."R_NAME" AND
"BAU"."BAAC02FK_CURR_CD"="CNR"."C_CD" AND
"BAU"."ASAC01FK_B_FUNC"="CNR"."B_FUNC_CD")
5 - access("CNR"."FM_CODE"='SP')
7 - filter("SANW"."EFF_STATUS_CODE"='A')
10 - filter("B"."PRIMARY_ACCT_IND"='N' OR "B"."PRIMARY_ACCT_IND"='Y')
13 - filter("D_RANK"=1)
16 - access("PS"."C_CD"="P"."C_CD" AND "PS"."C_ID_2"="P"."C_ID_2" AND
"PS"."CF_ID_2"="P"."CF_ID_2" AND "PS"."B_FUNC_2"="P"."B_FUNC_2" AND
"PS"."S_TYPE_2"="P"."S_TYPE_2" AND "PS"."A_TYPE_2"="P"."A_TYPE_2")
17 - filter("PS"."D_RANK"<>1)
23 - filter("B"."PRIMARY_ACCT_IND"=' ')

Related

Oracle Insert SQL Query Performance Tuning

I have an Insert query which is taking around 5-6 minutes to complete I plan to reduce timing to under 1 minutes.
I see a MERGE JOIN CARTESIAN in the explain plan so looking for ways to avoid it.
Below is concerned query and Explain Plan.
DB : Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production
INSERT INTO dictdm_discounts_perf
(
DISCOUNT_MIGRATION_ID,
DISCOUNT_NAME,
DISCOUNT_LEVEL,
RBM_PRODUCT_ID,
DISCOUNTED_OFFER_MIGR_ID,
DISCOUNTED_FLAT_OFFER_NAME,
DISCOUNTED_OFFERING_ID,
DISCOUNTED_OFFERING_NAME,
APPLY_MODE,
VALID_TO,
VALID_FROM,
DURATION,
DURATION_UNIT,
PRICE_COMPONENT_SPEC_ID,
PRICE_COMPONENT_SPEC_NAME,
ALT_PRICE,
ABSOLUTE_ALTERATION,
ALTERATION_IN_PERCENT,
TARIFF_ID,
DISCOUNT_RULE,
LEGACY_TARIFF_ID,
DISC_GROUP_ID,
DISC_GROUP_NAME
)
select
dsct.DISCOUNT_ID DISCOUNT_MIGRATION_ID
,dsct.NAME DISCOUNT_NAME
,(select lv.value from nc_list_values lv
where lv.list_value_id = DISCOUNT_LEVEL_VALUE_ID) DISCOUNT_LEVEL
,dsct.DISCOUNT_PRODUCT_ID RBM_PRODUCT_ID
,do.OFFER_MIGRATION_ID DISCOUNTED_OFFER_MIGR_ID
,do.FLAT_OFFERING_NAME DISCOUNTED_FLAT_OFFER_NAME
,do.OFFERING_ID DISCOUNTED_OFFERING_ID
,do.OFFERING_NAME DISCOUNTED_OFFERING_NAME
,(select lv.value from nc_list_values lv where lv.list_value_id = dsct.APPLY_MODE_VALUE_ID) APPLY_MODE
,dsct.AVAILABLE_TO VALID_TO
,dsct.AVAILABLE_FROM VALID_FROM
,dsct.DURATION DURATION
,(select lv.value from nc_list_values lv where lv.list_value_id = dsct.DURATION_UNIT_VALUE_ID) DURATION_UNIT
,pa.PRICE_SPEC_ID PRICE_COMPONENT_SPEC_ID
,(select o.name from nc_objects o where o.object_id = pa.PRICE_SPEC_ID) PRICE_COMPONENT_SPEC_NAME
,pa.PRICE_ALTERATION_ID ALT_PRICE
,decode(pa.DISC_AMOUNT_TYPE_VALUE_ID,9154646390213102438/*Absolute*/,pa.DISCOUNT_AMOUNT,null) ABSOLUTE_ALTERATION
,decode(pa.DISC_AMOUNT_TYPE_VALUE_ID,9154646390213102439/*Percentage*/,pa.DISCOUNT_AMOUNT,null) ALTERATION_IN_PERCENT
,pp.EXTERNAL_PRICE_PLAN_ID TARIFF_ID
,rl.RULE_ID DISCOUNT_RULE
,dsct.LEGACY_TARIFF_ID LEGACY_TARIFF_ID
,PD.DISCOUNT_GROUP_ID DISC_GROUP_ID
,O.NAME DISC_GROUP_NAME
from
POC_DISCOUNT dsct
join POC_DISCOUNT_TO_OBJECT d2o on d2o.DISCOUNT_ID = dsct.DISCOUNT_ID
join DICTDM_OFFERINGS do on decode(d2o.TYPE_ID,
9155001372713095116/*Offering*/, do.OFFERING_ID,
9155431485713090836/*Falt Offering*/, do.OFFER_MIGRATION_ID) = d2o.OBJECT_ID
or (d2o.TYPE_ID = 9155001372713095117/*Category*/ and instr(do.OFFERING_CATEGORY_ID,d2o.OBJECT_ID)>0)
left join POC_PRICE_ALTERATION pa on pa.DISCOUNT_ID = dsct.DISCOUNT_ID
left join PRICE_PLAN pp on pp.FLAT_OBJECT_ID = dsct.DISCOUNT_ID and pp.DISCOUNTED_OFFERING_ID = do.OFFERING_ID
left join POC_DISCOUNT_TO_RULE rl on rl.DISCOUNT_ID = dsct.DISCOUNT_ID
left join POC_DISCOUNT_TO_GROUP PD ON dsct.DISCOUNT_ID=PD.DISCOUNT_ID
left join NC_OBJECTS O ON O.OBJECT_ID=PD.DISCOUNT_GROUP_ID
where not exists (
select 0 from nc_params ofst
where ofst.object_id = do.offering_id
and ofst.attr_id = 7021759771013444983 /*Status*/
and ofst.list_value_id = 9140545748713273967 /*Discontinued*/
);
Plan hash value: 3564192537
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 10987 | 5203K| 4703 (1)| 00:00:01 |
| 1 | LOAD TABLE CONVENTIONAL | DICTDM_DISCOUNTS | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID | NC_LIST_VALUES | 1 | 23 | 1 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | XPKNC_LIST_VALUES | 1 | | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID | NC_LIST_VALUES | 1 | 23 | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | XPKNC_LIST_VALUES | 1 | | 1 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID | NC_LIST_VALUES | 1 | 23 | 1 (0)| 00:00:01 |
|* 7 | INDEX UNIQUE SCAN | XPKNC_LIST_VALUES | 1 | | 1 (0)| 00:00:01 |
| 8 | TABLE ACCESS BY INDEX ROWID | NC_OBJECTS | 1 | 32 | 1 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | XPKNC_OBJECTS | 1 | | 1 (0)| 00:00:01 |
|* 10 | HASH JOIN RIGHT OUTER | | 10987 | 5203K| 4696 (1)| 00:00:01 |
| 11 | TABLE ACCESS FULL | POC_PRICE_ALTERATION | 48 | 2160 | 3 (0)| 00:00:01 |
|* 12 | HASH JOIN RIGHT OUTER | | 9613 | 4130K| 4693 (1)| 00:00:01 |
| 13 | INDEX FULL SCAN | PK_POC_DISCOUNT_TO_RULE | 9 | 81 | 1 (0)| 00:00:01 |
| 14 | NESTED LOOPS OUTER | | 9176 | 3862K| 4692 (1)| 00:00:01 |
| 15 | NESTED LOOPS OUTER | | 9176 | 3575K| 4691 (1)| 00:00:01 |
|* 16 | HASH JOIN RIGHT OUTER | | 9176 | 3342K| 4690 (1)| 00:00:01 |
| 17 | TABLE ACCESS FULL | PRICE_PLAN | 1 | 39 | 3 (0)| 00:00:01 |
|* 18 | HASH JOIN | | 9176 | 2992K| 4687 (1)| 00:00:01 |
| 19 | TABLE ACCESS FULL | POC_DISCOUNT_TO_OBJECT | 43 | 1032 | 3 (0)| 00:00:01 |
| 20 | MERGE JOIN CARTESIAN | | 132K| 39M| 4683 (1)| 00:00:01 |
| 21 | NESTED LOOPS ANTI | | 3167 | 451K| 385 (0)| 00:00:01 |
| 22 | TABLE ACCESS FULL | DICTDM_OFFERINGS | 5660 | 608K| 102 (0)| 00:00:01 |
|* 23 | TABLE ACCESS BY INDEX ROWID BATCHED| NC_PARAMS | 44 | 1584 | 1 (0)| 00:00:01 |
|* 24 | INDEX RANGE SCAN | XIF12NC_PARAMS | 1 | | 1 (0)| 00:00:01 |
| 25 | BUFFER SORT | | 42 | 6888 | 4682 (1)| 00:00:01 |
| 26 | TABLE ACCESS FULL | POC_DISCOUNT | 42 | 6888 | 1 (0)| 00:00:01 |
| 27 | TABLE ACCESS BY INDEX ROWID BATCHED | POC_DISCOUNT_TO_GROUP | 1 | 26 | 1 (0)| 00:00:01 |
|* 28 | INDEX RANGE SCAN | IDX_DISCOUNT_TO_GROUP_D | 1 | | 1 (0)| 00:00:01 |
| 29 | TABLE ACCESS BY INDEX ROWID | NC_OBJECTS | 1 | 32 | 1 (0)| 00:00:01 |
|* 30 | INDEX UNIQUE SCAN | XPKNC_OBJECTS | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("LV"."LIST_VALUE_ID"=:B1)
5 - access("LV"."LIST_VALUE_ID"=:B1)
7 - access("LV"."LIST_VALUE_ID"=:B1)
9 - access("O"."OBJECT_ID"=:B1)
10 - access("PA"."DISCOUNT_ID"(+)="DSCT"."DISCOUNT_ID")
12 - access("RL"."DISCOUNT_ID"(+)="DSCT"."DISCOUNT_ID")
16 - access("PP"."DISCOUNTED_OFFERING_ID"(+)="DO"."OFFERING_ID" AND
"PP"."FLAT_OBJECT_ID"(+)="DSCT"."DISCOUNT_ID")
18 - access("D2O"."DISCOUNT_ID"="DSCT"."DISCOUNT_ID")
filter("D2O"."OBJECT_ID"=DECODE("D2O"."TYPE_ID",9155001372713095116,"DO"."OFFERING_ID",915543148571309083
6,"DO"."OFFER_MIGRATION_ID") OR "D2O"."TYPE_ID"=9155001372713095117 AND
INSTR("DO"."OFFERING_CATEGORY_ID",TO_CHAR("D2O"."OBJECT_ID"))>0)
23 - filter("OFST"."LIST_VALUE_ID"=9140545748713273967)
24 - access("OFST"."OBJECT_ID"="DO"."OFFERING_ID" AND "OFST"."ATTR_ID"=7021759771013444983)
28 - access("DSCT"."DISCOUNT_ID"="PD"."DISCOUNT_ID"(+))
30 - access("O"."OBJECT_ID"(+)="PD"."DISCOUNT_GROUP_ID")

A SQL query cost at least 10s

There is a SQL query in my project witch cost 10s+ every time.
SELECT * FROM (
SELECT TP.TOPIC_ID, CK.NAME
FROM TD_TOPIC TP
INNER JOIN TD_CIRCLE CK on CK.CIRCLE_ID = TP.CIRCLE_ID AND CK.VALID = 1 AND SYSDATE > CK.EFF_TIME
WHERE
TP.VALID = 1 AND TP.FORWARD_FROM_TOPIC_ID = 0
AND (( TP.TOPIC_TYPE = 1 AND TP.APPROVAL_STATUS = 1) OR TP.TOPIC_TYPE IN (0, 2))
AND (TP.TOPIC_TYPE != 2 OR EXISTS (
SELECT 1 FROM TD_VOTE_TOPIC_CONFIG CFG
WHERE CFG.TOPIC_ID=TP.TOPIC_ID AND SYSDATE > CFG.EFFECT_TIME
))
AND (
EXISTS (
SELECT 1 FROM TD_TOPIC_TAG TG WHERE TG.TOPIC_ID=TP.TOPIC_ID
AND TG.TAG_ID IN (1, 2)
)
OR EXISTS (
SELECT 1 FROM TD_CIRCLE_TAG CTG WHERE CTG.CIRCLE_ID=CK.CIRCLE_ID
AND CTG.TAG_ID IN (1, 2)
)
)
ORDER BY TP.CREATE_TIME DESC
) WHERE ROWNUM<21
This is the query plan. It takes too many time on TABLE FULL ACCESS of TP_TOPIC.
3 -------------------------------------------------------------------------------------------------------------
4 | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
5 -------------------------------------------------------------------------------------------------------------
6 | 0 | SELECT STATEMENT | | 20 | 4560 | 4286 (1)| 00:00:52 |
7 |* 1 | COUNT STOPKEY | | | | | |
8 | 2 | VIEW | | 48986 | 10M| 4286 (1)| 00:00:52 |
9 |* 3 | SORT ORDER BY STOPKEY | | 48986 | 6936K| 4286 (1)| 00:00:52 |
10 | 4 | CONCATENATION | | | | | |
11 |* 5 | FILTER | | | | | |
12 |* 6 | HASH JOIN | | 24516 | 3471K| 2140 (1)| 00:00:26 |
13 |* 7 | TABLE ACCESS FULL | TD_CIRCLE | 415 | 44820 | 11 (0)| 00:00:01 |
14 |* 8 | TABLE ACCESS FULL | TD_TOPIC | 75205 | 2717K| 2128 (1)| 00:00:26 |
15 |* 9 | TABLE ACCESS BY INDEX ROWID| TD_CIRCLE_TAG | 1 | 8 | 2 (0)| 00:00:01 |
16 |* 10 | INDEX RANGE SCAN | IDX_TD_CIRCLE_TAG_TAG_ID | 1 | | 1 (0)| 00:00:01 |
17 |* 11 | TABLE ACCESS BY INDEX ROWID| TD_VOTE_TOPIC_CONFIG | 1 | 13 | 2 (0)| 00:00:01 |
18 |* 12 | INDEX RANGE SCAN | IDX_VTCFG_TOPICID | 1 | | 1 (0)| 00:00:01 |
19 |* 13 | FILTER | | | | | |
20 |* 14 | HASH JOIN | | 24516 | 3471K| 2140 (1)| 00:00:26 |
21 |* 15 | TABLE ACCESS FULL | TD_CIRCLE | 415 | 44820 | 11 (0)| 00:00:01 |
22 |* 16 | TABLE ACCESS FULL | TD_TOPIC | 75205 | 2717K| 2128 (1)| 00:00:26 |
23 |* 17 | TABLE ACCESS BY INDEX ROWID| TD_CIRCLE_TAG | 1 | 8 | 2 (0)| 00:00:01 |
24 |* 18 | INDEX RANGE SCAN | IDX_TD_CIRCLE_TAG_TAG_ID | 1 | | 1 (0)| 00:00:01 |
25 |* 19 | TABLE ACCESS BY INDEX ROWID| TD_TOPIC_TAG | 1 | 8 | 2 (0)| 00:00:01 |
26 |* 20 | INDEX RANGE SCAN | IDX_TD_TOPIC_TAG_TAG_ID | 1 | | 1 (0)| 00:00:01 |
27 |* 21 | TABLE ACCESS BY INDEX ROWID| TD_VOTE_TOPIC_CONFIG | 1 | 13 | 2 (0)| 00:00:01 |
28 |* 22 | INDEX RANGE SCAN | IDX_VTCFG_TOPICID | 1 | | 1 (0)| 00:00:01 |
29 -------------------------------------------------------------------------------------------------------------
Table TD_TOPIC is very large. And I found TABLE ACCESS (FULL) of TD_TOPIC. Maybe it is the problem. But I don't know how to make it access by index yet.
SELECT *
FROM (
SELECT TP.TOPIC_ID,
CK.NAME
FROM TD_TOPIC TP
INNER JOIN TD_CIRCLE CK
ON CK.CIRCLE_ID = TP.CIRCLE_ID
LEFT JOIN TD_VOTE_TOPIC_CONFIG CFG
ON CFG.TOPIC_ID=TP.TOPIC_ID
LEFT JOIN TD_CIRCLE_TAG CTG
ON CTG.CIRCLE_ID=CK.CIRCLE_ID
WHERE TP.VALID = 1
AND TP.FORWARD_FROM_TOPIC_ID = 0
AND CK.VALID = 1
AND CK.EFF_TIME < SYSDATE
AND (
(
TP.TOPIC_TYPE = 1
AND TP.APPROVAL_STATUS = 1
)
OR TP.TOPIC_TYPE IN (0, 2)
)
AND (
TP.TOPIC_TYPE != 2
OR
CFG.EFFECT_TIME < SYSDATE
)
AND (
(
TG.TOPIC_ID IS NOT NULL
AND TG.TAG_ID IN (1, 2)
)
OR
(
CTG.CIRCLE_ID IS NOT NULL
AND CTG.TAG_ID IN (1, 2)
)
)
ORDER BY TP.CREATE_TIME DESC
)
WHERE ROWNUM<21

Need help to optimize Oracle query in 12c

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

sql long running query requires optimization

Oracle query.
The following query takes some time to execute:
SELECT GCCOM_ACCOUNT_CONTRACT.ID_ACCOUNT_CONTRACT
FROM GCCOM_ACCOUNT_CONTRACT, GCCOM_ACCOUNT_GROUP
WHERE
GCCOM_ACCOUNT_CONTRACT.ID_ACCOUNT_GROUP = GCCOM_ACCOUNT_GROUP.ID_ACCOUNT_GROUP (+) AND
EXISTS (SELECT 1 FROM GCCOM_CONTRACTED_SERVICE
WHERE ID_ACCOUNT_CONTRACT = GCCOM_ACCOUNT_CONTRACT.ID_ACCOUNT_CONTRACT AND
STATUS = 'ESTSC00002' AND
DROP_DATE IS NULL ) AND
EXISTS (SELECT 1 FROM GCCOM_SEND_SERVICE
WHERE (ID_ACCOUNT_CONTRACT = GCCOM_ACCOUNT_CONTRACT.ID_ACCOUNT_CONTRACT OR
ID_ACCOUNT_GROUP = GCCOM_ACCOUNT_GROUP.ID_ACCOUNT_GROUP)
) AND
(( GCCOM_ACCOUNT_CONTRACT.ACCOUNT_CODE between 200000001 AND 900468243))
ORDER BY
GCCOM_ACCOUNT_CONTRACT.ID_COMPANY,
GCCOM_ACCOUNT_GROUP.ID_ACCOUNT_GROUP,
GCCOM_ACCOUNT_CONTRACT.ACCOUNT_CODE
The explain plan shows as follows:
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 391653930
------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 45 | | 570K (1)| 01:54:06 | | |
| 1 | SORT ORDER BY | | 1 | 45 | 12M| 570K (1)| 01:54:06 | | |
|* 2 | FILTER | | | | | | | | |
| 3 | NESTED LOOPS OUTER | | 255K| 10M| | 17381 (1)| 00:03:29 | | |
|* 4 | HASH JOIN RIGHT SEMI | | 255K| 9979K| 8648K| 17380 (1)| 00:03:29 | | |
| 5 | PARTITION HASH ALL | | 260K| 5592K| | 7175 (1)| 00:01:27 | 1 | 16 |
|* 6 | TABLE ACCESS FULL | GCCOM_CONTRACTED_SERVICE | 260K| 5592K| | 7175 (1)| 00:01:27 | 1 | 16 |
|* 7 | TABLE ACCESS FULL | GCCOM_ACCOUNT_CONTRACT | 810K| 13M| | 8627 (1)| 00:01:44 | | |
|* 8 | INDEX UNIQUE SCAN | PK_GCCOM_ACCOUNT_GROUP | 1 | 5 | | 1 (0)| 00:00:01 | | |
| 9 | CONCATENATION | | | | | | | | |
| 10 | TABLE ACCESS BY GLOBAL INDEX ROWID| GCCOM_SEND_SERVICE | 1 | 7 | | 1 (0)| 00:00:01 | ROWID | ROWID |
|* 11 | INDEX RANGE SCAN | IDX_GCCOMSENDSERVICE_27 | 1 | | | 1 (0)| 00:00:01 | | |
|* 12 | TABLE ACCESS BY GLOBAL INDEX ROWID| GCCOM_SEND_SERVICE | 2 | 14 | | 1 (0)| 00:00:01 | ROWID | ROWID |
|* 13 | INDEX RANGE SCAN | IDX_GCCOMSENDSERVICE_04 | 1 | | | 1 (0)| 00:00:01 | | |
------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------
2 - filter( EXISTS (SELECT 0 FROM "GCCOM_SEND_SERVICE" "GCCOM_SEND_SERVICE"<not feasible>)
4 - access("ID_ACCOUNT_CONTRACT"="GCCOM_ACCOUNT_CONTRACT"."ID_ACCOUNT_CONTRACT")
6 - filter("DROP_DATE" IS NULL AND "STATUS"='ESTSC00002')
7 - filter("GCCOM_ACCOUNT_CONTRACT"."ACCOUNT_CODE">=200000001 AND "GCCOM_ACCOUNT_CONTRACT"."ACCOUNT_CODE"<=900468243)
8 - access("GCCOM_ACCOUNT_CONTRACT"."ID_ACCOUNT_GROUP"="GCCOM_ACCOUNT_GROUP"."ID_ACCOUNT_GROUP"(+))
11 - access("ID_ACCOUNT_CONTRACT"=:B1)
12 - filter(LNNVL("ID_ACCOUNT_CONTRACT"=:B1))
13 - access("ID_ACCOUNT_GROUP"=:B1)
32 filas seleccionadas.
The average cardinality of table looks as follows:
select count(*) from GCCOM_ACCOUNT_CONTRACT >> rows: 810412
select avg(distinct ID_ACCOUNT_GROUP) from GCCOM_ACCOUNT_CONTRACT >> cardinality: 87173
Highly indexed.
Tried many things, but useless.
Any idea ?

Sql tuning using table and view

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