How to debug an Oracle query given an explain plan? - sql

IMAGE OF TOAD: query waits
WITH
NJ AS (SELECT CNATJUR FROM RE_CD.CDTD005_NATUR_JURIDICA WHERE DESCRICAO = 'Particulares' AND DTEND_VER = '9999-12-31 00:00' ),
PAISES AS (SELECT PAIS_BST FROM RE_CD.CDTD006_PAISES WHERE GRUPO_PAIS = 'RESTO UNIAO EUROPEIA' AND DTEND_VER = '9999-12-31 00:00' ),
GAR AS (SELECT /*+PARALLEL(4)*/ CCONTA, CREFERENCIA_IMP FROM RE_DM.DMTD002_GAR_CONTRATO WHERE TIPO_GAR = 'GAR REAL' AND TIPO_GAR2 = 'GAR DINERARIA' AND FLAG_PRIORIDADE = 1 AND IDVERSAO = (SELECT MAX(IDVERSAO) FROM RE_DM.DMTD001_VERSOES WHERE TABELA = 'RE_DM.DMTD002_GAR_CONTRATO' AND DTEND_VER = '9999-12-31 00:00' ) )
SELECT /*+PARALLEL(4)*/ MOROS.COD_PERIMETRO, MOROS.SOCIEDADE
FROM RE_DM.DMTF020_MOROS MOROS
INNER JOIN GAR ON MOROS.CCONTA = GAR.CCONTA AND MOROS.CREFERENCIA = GAR.CREFERENCIA_IMP
INNER JOIN NJ ON MOROS.COD_NATJUR = NJ.CNATJUR
INNER JOIN PAISES ON MOROS.COD_PAIS = PAISES.PAIS_BST
WHERE MOROS.IDVERSAO = 167
AND MOROS.SEGMENTO <> 'PC' AND MOROS.SEGMENTO <> 'LO' AND MOROS.SEGMENTO <> 'GA'
AND MOROS.SEGMENTO <> 'G1' AND MOROS.SEGMENTO <> 'G2' AND MOROS.SEGMENTO <> 'G3'
AND MOROS.INPUT = 'IMP'
AND MOROS.FLAG_MOROSIDADE = 0;
Plan hash value: 441958758
----------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 76752 | 16M| 22115 (1)| 00:01:07 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ20002 | 76752 | 16M| 22113 (1)| 00:01:07 | Q2,02 | P->S | QC (RAND) |
|* 3 | HASH JOIN | | 76752 | 16M| 22113 (1)| 00:01:07 | Q2,02 | PCWP | |
| 4 | PX RECEIVE | | 42 | 1512 | 2 (0)| 00:00:01 | Q2,02 | PCWP | |
| 5 | PX SEND BROADCAST | :TQ20000 | 42 | 1512 | 2 (0)| 00:00:01 | Q2,00 | P->P | BROADCAST |
| 6 | PX BLOCK ITERATOR | | 42 | 1512 | 2 (0)| 00:00:01 | Q2,00 | PCWC | |
|* 7 | TABLE ACCESS FULL | CDTD006_PAISES | 42 | 1512 | 2 (0)| 00:00:01 | Q2,00 | PCWP | |
|* 8 | HASH JOIN | | 237K| 41M| 22110 (1)| 00:01:07 | Q2,02 | PCWP | |
| 9 | PX RECEIVE | | 23 | 1150 | 2 (0)| 00:00:01 | Q2,02 | PCWP | |
| 10 | PX SEND BROADCAST | :TQ20001 | 23 | 1150 | 2 (0)| 00:00:01 | Q2,01 | P->P | BROADCAST |
| 11 | PX BLOCK ITERATOR | | 23 | 1150 | 2 (0)| 00:00:01 | Q2,01 | PCWC | |
|* 12 | TABLE ACCESS FULL | CDTD005_NATUR_JURIDICA | 23 | 1150 | 2 (0)| 00:00:01 | Q2,01 | PCWP | |
| 13 | NESTED LOOPS | | | | | | Q2,02 | PCWP | |
| 14 | NESTED LOOPS | | 795K| 100M| 22105 (1)| 00:01:07 | Q2,02 | PCWP | |
| 15 | PX BLOCK ITERATOR | | | | | | Q2,02 | PCWC | |
|* 16 | TABLE ACCESS FULL | DMTD002_GAR_CONTRATO | 6357 | 341K| 4423 (1)| 00:00:14 | Q2,02 | PCWP | |
| 17 | SORT AGGREGATE | | 1 | 42 | | | Q2,02 | PCWP | |
| 18 | PX COORDINATOR | | | | | | | | |
| 19 | PX SEND QC (RANDOM) | :TQ10000 | 1 | 42 | | | Q1,00 | P->S | QC (RAND) |
| 20 | SORT AGGREGATE | | 1 | 42 | | | Q1,00 | PCWP | |
| 21 | PX BLOCK ITERATOR | | 1 | 42 | 2 (0)| 00:00:01 | Q1,00 | PCWC | |
|* 22 | TABLE ACCESS FULL | DMTD001_VERSOES | 1 | 42 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
|* 23 | INDEX RANGE SCAN | DMTF020_MOROS_INDEX2 | 21 | | 1 (0)| 00:00:01 | Q2,02 | PCWP | |
|* 24 | TABLE ACCESS BY INDEX ROWID| DMTF020_MOROS | 125 | 9750 | 3 (0)| 00:00:01 | Q2,02 | PCWP | |
----------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("MOROS"."COD_PAIS"="PAIS_BST")
7 - filter("GRUPO_PAIS"='RESTO UNIAO EUROPEIA' AND "DTEND_VER"='9999-12-31 00:00')
8 - access("MOROS"."COD_NATJUR"="CNATJUR")
12 - filter("DESCRICAO"='Particulares' AND "DTEND_VER"='9999-12-31 00:00')
16 - filter("TIPO_GAR2"='GAR DINERARIA' AND "TIPO_GAR"='GAR REAL' AND "FLAG_PRIORIDADE"=1 AND "IDVERSAO"= (SELECT
MAX(SYS_OP_CSR(SYS_OP_MSR(MAX("IDVERSAO")),0)) FROM "RE_DM"."DMTD001_VERSOES" "DMTD001_VERSOES" WHERE
"TABELA"='RE_DM.DMTD002_GAR_CONTRATO' AND "DTEND_VER"='9999-12-31 00:00'))
22 - filter("TABELA"='RE_DM.DMTD002_GAR_CONTRATO' AND "DTEND_VER"='9999-12-31 00:00')
23 - access("MOROS"."CREFERENCIA"="CREFERENCIA_IMP")
filter("MOROS"."CREFERENCIA" IS NOT NULL)
24 - filter("MOROS"."IDVERSAO"=167 AND "MOROS"."CCONTA" IS NOT NULL AND TO_NUMBER("MOROS"."FLAG_MOROSIDADE")=0 AND
"MOROS"."INPUT"='IMP' AND "MOROS"."SEGMENTO"<>'GA' AND "MOROS"."SEGMENTO"<>'G1' AND "MOROS"."SEGMENTO"<>'PC' AND
"MOROS"."SEGMENTO"<>'G2' AND "MOROS"."SEGMENTO"<>'G3' AND "MOROS"."SEGMENTO"<>'LO' AND "MOROS"."CCONTA"="CCONTA")
Note
-----
- dynamic sampling used for this statement (level=5)
- Degree of Parallelism is 4 because of hint
Does anyone see something fishy with this "explain plan"? I've added indexes, I ran statistics, rebuild indexes... the server is a laptop with 8gb ram, SSD hard drive and i7 cpu.
Any ideas?

Obviously, look for your full table scans, but they aren't always the culprit. The problem appears to be in the nested loops.
I would focus on DMTD002_GAR_CONTRATO, and perhaps place an index to eliminate the
full table scan; however, I suspect that the main problem may be in the subquery in the where clause that creates table alias "GAR".
It would be worth experimenting with a hardcoded value rather than a subquery to see if it improves performance.

(Posted on behalf of OP).
Our temp tablespace was super tiny. After increasing the size all things start to go faster and smoother. Thanks to all that helped.

Related

Is there a way to fine-tune my Oracle SQL code?

Is there a way to fine-tune my Oracle SQL code below? All tables are residing in the same schema.
MERGE INTO W_PURCH_COST_F TGT USING
(SELECT
/*+ PARALLEL(8) */
cost.INTEGRATION_ID,
cost.X_RECEIVED_ON_DT,
COALESCE(gaap.ROW_WID,0) X_GAAP_EXCH_RATE_WID
FROM W_Purch_Cost_F_3955 cost
JOIN W_DAY_D wday
ON TRUNC(cost.X_RECEIVED_ON_DT)=TRUNC(wday.CALENDAR_DATE)
LEFT OUTER JOIN WC_GAAP_EXCH_RATE_G gaap
ON gaap.PERIOD =wday.PER_NAME_ENT_PERIOD
) SRC ON (TGT.INTEGRATION_ID = SRC.INTEGRATION_ID AND TGT.DATASOURCE_NUM_ID = 310)
WHEN MATCHED THEN
UPDATE SET TGT.X_GAAP_EXCH_RATE_WID = SRC.X_GAAP_EXCH_RATE_WID;
TGT is the target table and SRC is the source table, all residing in a staging environment and the same schema.
Plan hash value: 679420733
-----------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------------------------------------
| 0 | MERGE STATEMENT | | 18G| 256G| | 186K (5)| 00:00:15 | | | |
| 1 | MERGE | W_PURCH_COST_F | | | | | | | | |
| 2 | PX COORDINATOR | | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10002 | 18G| 10T| | 186K (5)| 00:00:15 | Q1,02 | P->S | QC (RAND) |
| 4 | VIEW | | | | | | | Q1,02 | PCWP | |
|* 5 | HASH JOIN RIGHT OUTER BUFFERED| | 18G| 10T| | 186K (5)| 00:00:15 | Q1,02 | PCWP | |
| 6 | TABLE ACCESS FULL | WC_GAAP_EXCH_RATE_G | 16261 | 269K| | 5 (0)| 00:00:01 | Q1,02 | PCWP | |
|* 7 | HASH JOIN | | 398M| 228G| 767M| 179K (1)| 00:00:15 | Q1,02 | PCWP | |
| 8 | PX RECEIVE | | 10M| 6014M| | 18997 (1)| 00:00:02 | Q1,02 | PCWP | |
| 9 | PX SEND HASH | :TQ10000 | 10M| 6014M| | 18997 (1)| 00:00:02 | Q1,00 | P->P | HASH |
| 10 | PX BLOCK ITERATOR | | 10M| 6014M| | 18997 (1)| 00:00:02 | Q1,00 | PCWC | |
|* 11 | TABLE ACCESS FULL | W_PURCH_COST_F | 10M| 6014M| | 18997 (1)| 00:00:02 | Q1,00 | PCWP | |
| 12 | PX RECEIVE | | 398M| 13G| | 28134 (2)| 00:00:03 | Q1,02 | PCWP | |
| 13 | PX SEND HASH | :TQ10001 | 398M| 13G| | 28134 (2)| 00:00:03 | Q1,01 | P->P | HASH |
|* 14 | HASH JOIN | | 398M| 13G| | 28134 (2)| 00:00:03 | Q1,01 | PCWP | |
| 15 | TABLE ACCESS FULL | W_DAY_D | 10790 | 210K| | 29 (0)| 00:00:01 | Q1,01 | PCWP | |
| 16 | PX BLOCK ITERATOR | | 383M| 6219M| | 27963 (2)| 00:00:03 | Q1,01 | PCWC | |
| 17 | TABLE ACCESS FULL | W_PURCH_COST_F_3955 | 383M| 6219M| | 27963 (2)| 00:00:03 | Q1,01 | PCWP | |
-----------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("GAAP"."PERIOD"(+)="WDAY"."PER_NAME_ENT_PERIOD")
7 - access("TGT"."INTEGRATION_ID"="COST"."INTEGRATION_ID")
11 - filter("TGT"."DATASOURCE_NUM_ID"=310)
14 - access(TRUNC(INTERNAL_FUNCTION("COST"."X_RECEIVED_ON_DT"))=TRUNC(INTERNAL_FUNCTION("WDAY"."CALENDAR_DATE")))
Note
-----
- dynamic statistics used: dynamic sampling (level=AUTO)
- Degree of Parallelism is 8 because of hint
- PDML is disabled in current session

Why does this SELECT statement take more than two hours?

I have two tables A & B. A has 6,760,636 records and B has 452,175,960 records. Here is the SELECT Statement I'm using:
SELECT /*+ parallel (T,1) */
T.*
FROM TABLE_A T,
TABLE_B P
WHERE T.DESTINATION = P.DESTINATION
AND T.SAIL_DATE = P.SAIL_DATE
AND T.PACKAGE_TYPE = P.PACKAGE_TYPE
AND T.CABIN_CATEGORY = P.CABIN_CATEGORY
AND T.BOOKING_SOURCE = P.BOOKING_SOURCE
AND T.FARE_TYPE = P.FARE_TYPE
AND T.POST_DATE = P.POST_DATE;
I tried creating the index on TABLE_A, but still it is not considering the INDEX and doing a FULL TABLE SCAN.
The EXPLAIN PLAN for above is
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6760K| 1805M| 747K (1)| | | |
| 1 | SORT AGGREGATE | | 1 | 48 | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| CL_PRICING_CONTROLS | 1 | 48 | 2 (0)| | | |
| 3 | INDEX RANGE SCAN | CL_PRICING_CONTROLS_IX3 | 1 | | 1 (0)| | | |
| 4 | PX COORDINATOR | | | | | | | |
| 5 | PX SEND QC (RANDOM) | :TQ10002 | 6760K| 1805M| 747K (1)| Q1,02 | P->S | QC (RAND) |
| 6 | HASH JOIN | | 6760K| 1805M| 747K (1)| Q1,02 | PCWP | |
| 7 | PX RECEIVE | | 6760K| 1437M| 1443 (1)| Q1,02 | PCWP | |
| 8 | PX SEND HASH | :TQ10001 | 6760K| 1437M| 1443 (1)| Q1,01 | P->P | HASH |
| 9 | PX BLOCK ITERATOR | | 6760K| 1437M| 1443 (1)| Q1,01 | PCWC | |
| 10 | TABLE ACCESS FULL | TMP_RES_PRICE_CONTROL_111 | 6760K| 1437M| 1443 (1)| Q1,01 | PCWP | |
| 11 | BUFFER SORT | | | | | Q1,02 | PCWC | |
| 12 | PX RECEIVE | | 450M| 23G| 746K (1)| Q1,02 | PCWP | |
| 13 | PX SEND HASH | :TQ10000 | 450M| 23G| 746K (1)| | S->P | HASH |
| 14 | INDEX FULL SCAN | CL_PRICING_CONTROLS_IX1 | 450M| 23G| 746K (1)| | | |
I tried parallel query on both tables as below
SELECT /*+ PARALLEL(T, 32) PARALLEL(P, 32)*/
T.*
FROM TABLE_A T,
TABLE_B P
WHERE T.DESTINATION = P.DESTINATION
AND T.SAIL_DATE = P.SAIL_DATE
AND T.PACKAGE_TYPE = P.PACKAGE_TYPE
AND T.CABIN_CATEGORY = P.CABIN_CATEGORY
AND T.BOOKING_SOURCE = P.BOOKING_SOURCE
AND T.FARE_TYPE = P.FARE_TYPE
AND T.POST_DATE = P.POST_DATE;
But this results in the EXPLAIN PLAN as below, where I see CPU with lower Cost, but still it is taking two hours.
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6760K| 1805M| 59345 (1)| | | |
| 1 | SORT AGGREGATE | | 1 | 48 | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| CL_PRICING_CONTROLS | 1 | 48 | 2 (0)| | | |
| 3 | INDEX RANGE SCAN | CL_PRICING_CONTROLS_IX3 | 1 | | 1 (0)| | | |
| 4 | PX COORDINATOR | | | | | | | |
| 5 | PX SEND QC (RANDOM) | :TQ10002 | 6760K| 1805M| 59345 (1)| Q1,02 | P->S | QC (RAND) |
| 6 | HASH JOIN BUFFERED | | 6760K| 1805M| 59345 (1)| Q1,02 | PCWP | |
| 7 | PX RECEIVE | | 6760K| 1437M| 1443 (1)| Q1,02 | PCWP | |
| 8 | PX SEND HASH | :TQ10000 | 6760K| 1437M| 1443 (1)| Q1,00 | P->P | HASH |
| 9 | PX BLOCK ITERATOR | | 6760K| 1437M| 1443 (1)| Q1,00 | PCWC | |
| 10 | TABLE ACCESS FULL | TMP_RES_PRICE_CONTROL_111 | 6760K| 1437M| 1443 (1)| Q1,00 | PCWP | |
| 11 | PX RECEIVE | | 450M| 23G| 57858 (1)| Q1,02 | PCWP | |
| 12 | PX SEND HASH | :TQ10001 | 450M| 23G| 57858 (1)| Q1,01 | P->P | HASH |
| 13 | PX BLOCK ITERATOR | | 450M| 23G| 57858 (1)| Q1,01 | PCWC | |
| 14 | TABLE ACCESS FULL | CL_PRICING_CONTROLS | 450M| 23G| 57858 (1)| Q1,01 | PCWP | |
Please look at your query, specifically at its WHERE clause. It consists entirely of join conditions. It could be rewritten using the ANSI-92 syntax to this:
SELECT /*+ parallel (T,1) */
T.*
FROM TABLE_A T
inner join TABLE_B P
on T.DESTINATION = P.DESTINATION
AND T.SAIL_DATE = P.SAIL_DATE
AND T.PACKAGE_TYPE = P.PACKAGE_TYPE
AND T.CABIN_CATEGORY = P.CABIN_CATEGORY
AND T.BOOKING_SOURCE = P.BOOKING_SOURCE
AND T.FARE_TYPE = P.FARE_TYPE
AND T.POST_DATE = P.POST_DATE;
So every row in each table has to be considered. Clearly full table scans are the only plausible access path.
Building a composite index on all columns in the JOIN clause is unlikely to change this. You are selecting all the columns from TABLE_A, so the database needs to visit the table anyway.
Unless the number of records in the intersection between the two tables is incredibly small it will be more efficient to read the tables in multi-block reads rather than index scans with table row look-ups. As it is, you're selecting almost one-in-six of all the rows in a half-billion row table. How would an index make that faster?
Incidentally, how did you decide on the degree of parallelism? How many CPUs does your server have? What other processes are running concurrently? What is the value of MAX_PARALLEL_SERVERS? Find out more.

PerformanceTune#Huge Table Size

Looking for a help in PT.
Attaching the psuedo query..
There are 3 tables used below all are having huge chunk of records
t2 ~ 10 million,
t1 ~ 15 million ,
t3 ~ 8 million
Used Parallel Hints . But not much help in cost.. Cost is shooting to more than 200k
(SELECT /*+ parallel (a,8) parallel (b,8)*/
DISTINCT B.ACCNT_NUM
FROM s1.t1 a, s2.t2 b
WHERE a.accnt_num = b.accnt_num
AND product_key IN (SELECT product_key FROM s3.t3 WHERE prod_type_cd = 'S')
AND a.active_flg = 'Y'
AND a.deleted_flg = 'N'
GROUP BY B.ACCNT_NUM, a.product_key
HAVING COUNT (*) > 1)
Plan:
| 0 | SELECT STATEMENT
| 1 | 54 | 204K (1)| 00:47:39 | | | | | | | 1 | PX COORDINATOR | | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10004 | 1 | 54 | 204K (1)| 00:47:39 | | | Q1,04 | P->S | QC (RAND) |
| 3 | HASH UNIQUE | | 1 | 54 | 204K (1)| 00:47:39 | | | Q1,04 | PCWP | |
| 4 | PX RECEIVE | | 1 | 54 | 204K (1)| 00:47:39 | | | Q1,04 | PCWP | |
| 5 | PX SEND HASH | :TQ10003 | 1 | 54 | 204K (1)| 00:47:39 | | | Q1,03 | P->P | HASH |
|* 6 | FILTER | | | | | | | | Q1,03 | PCWC | |
| 7 | HASH GROUP BY | | 1 | 54 | 204K (1)| 00:47:39 | | | Q1,03 | PCWP | |
| 8 | PX RECEIVE | | 1 | 54 | 204K (1)| 00:47:39 | | | Q1,03 | PCWP | |
| 9 | PX SEND HASH | :TQ10002 | 1 | 54 | 204K (1)| 00:47:39 | | | Q1,02 | P->P | HASH |
| 10 | HASH GROUP BY | | 1 | 54 | 204K (1)| 00:47:39 | | | Q1,02 | PCWP | |
|* 11 | HASH JOIN | | 90476 | 4771K| 204K (1)| 00:47:39 | | | Q1,02 | PCWP | |
| 12 | PX RECEIVE | | 22572 | 462K| 66147 (1)| 00:15:27 | | | Q1,02 | PCWP | |
| 13 | PX SEND BROADCAST | :TQ10001 | 22572 | 462K| 66147 (1)| 00:15:27 | | | Q1,01 | P->P | BROADCAST |
|* 14 | TABLE ACCESS BY LOCAL INDEX ROWID| table 1 | 22572 | 462K| 66147 (1)| 00:15:27 | | | Q1,01 | PCWP | |
| 15 | NESTED LOOPS | | 135K| 4893K| 198K (1)| 00:46:19 | | | Q1,01 | PCWP | |
| 16 | BUFFER SORT | | | | | | | | Q1,01 | PCWC | |
| 17 | PX RECEIVE | | | | | | | | Q1,01 | PCWP | |
| 18 | PX SEND BROADCAST | :TQ10000 | | | | | | | | S->P | BROADCAST |
| 19 | SORT UNIQUE | | 6 | 96 | 3 (0)| 00:00:01 | | | | | |
|* 20 | TABLE ACCESS FULL | table 3 | 6 | 96 | 3 (0)| 00:00:01 | | | | | |
| 21 | PX PARTITION HASH ALL | | 65923 | | 207 (1)| 00:00:03 | 1 | 32 | Q1,01 | PCWC | |
|* 22 | INDEX RANGE SCAN | I_table1 | 65923 | | 207 (1)| 00:00:03 | 33 | 64 | Q1,01 | PCWP | |
| 23 | PX BLOCK ITERATOR | | 12M| 201M| 5738 (2)| 00:01:21 | | | Q1,02 | PCWC | |
| 24 | INDEX FAST FULL SCAN | I_table 2 | 12M| 201M| 5738 (2)| 00:01:21 | | | Q1,02 | PCWP | |
Regards
So the eye is drawn to this line of the Explain Plan:
|* 20 | TABLE ACCESS FULL | table 3 | 6 | 96 | 3 (0)| 00:00:01 | | | | | |
The optimizer on the other hand thinks it has six rows, and so regards it as a very cheap operation. The OP says that t3 has ~ 8 million rows. A Full Table Scan of that will be pretty expensive.
The optimizer is clever but relies on accurate table and index statistics. It seems a good place to start would be a review of the pertinent statistics, and refreshing the ones which are inaccurate. Find out more.

Pushing predicate in a view

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.

Connect By Level In Subquery Slow

I am using a connect_by_level subquery in an Oracle database to supply dates to join with another table. The connect by level appears to be causing the query to run very slowly. Here is my slow query:
select t.code, d.month_end, count(*)
from device t,
(select add_months(trunc(sysdate, 'MM'), - (level - 1)) - 1 MONTH_END
from dual
connect by level <= 1) d
where (d.month_end between t.date and t.exp_date)
group by t.code, d.month_end
The slow query above took about 2 hours to run the other day. The query below which should be equivalent runs in less than 30 seconds:
select t.code, trunc(sysdate, 'MM') - 1 month_end, count(*)
from device t
where ((trunc(sysdate, 'MM') - 1) between t.date and t.exp_date)
group by t.code
Ultimately, I want the 1st query to return data for the past 24 months, but I need to figure out why it is running so slowly with only 1 month as the criteria. Any suggestions on what is causing the slow completion time with the connect by level query?
Edit to add explain plan output for slow query:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | TQ |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 520 | 65520 | 134K (1)| 00:00:03 | | | | | |
| 1 | PX COORDINATOR | | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10006 | 520 | 65520 | 134K (1)| 00:00:03 | | | Q1,06 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | 520 | 65520 | 134K (1)| 00:00:03 | | | Q1,06 | PCWP | |
| 4 | PX RECEIVE | | 520 | 65520 | 134K (1)| 00:00:03 | | | Q1,06 | PCWP | |
| 5 | PX SEND HASH | :TQ10005 | 520 | 65520 | 134K (1)| 00:00:03 | | | Q1,05 | P->P | HASH |
| 6 | HASH GROUP BY | | 520 | 65520 | 134K (1)| 00:00:03 | | | Q1,05 | PCWP | |
|* 7 | HASH JOIN OUTER | | 520 | 65520 | 134K (1)| 00:00:03 | | | Q1,05 | PCWP | |
| 8 | PX RECEIVE | | 520 | 48880 | 134K (1)| 00:00:03 | | | Q1,05 | PCWP | |
| 9 | PX SEND HASH | :TQ10003 | 520 | 48880 | 134K (1)| 00:00:03 | | | Q1,03 | P->P | HASH |
|* 10 | HASH JOIN OUTER BUFFERED | | 520 | 48880 | 134K (1)| 00:00:03 | | | Q1,03 | PCWP | |
| 11 | PX RECEIVE | | | | | | | | Q1,03 | PCWP | |
| 12 | PX SEND HASH | :TQ10001 | | | | | | | Q1,01 | P->P | HASH |
| 13 | NESTED LOOPS | | | | | | | | Q1,01 | PCWP | |
| 14 | NESTED LOOPS | | 276 | 13800 | 50303 (0)| 00:00:01 | | | Q1,01 | PCWP | |
| 15 | BUFFER SORT | | | | | | | | Q1,01 | PCWC | |
| 16 | PX RECEIVE | | | | | | | | Q1,01 | PCWP | |
| 17 | PX SEND BROADCAST | :TQ10000 | | | | | | | | S->P | BROADCAST |
| 18 | VIEW | | 1 | 6 | 3 (0)| 00:00:01 | | | | | |
|* 19 | CONNECT BY WITHOUT FILTERING| | | | | | | | | | |
| 20 | FAST DUAL | | 1 | | 3 (0)| 00:00:01 | | | | | |
| 21 | PX PARTITION RANGE ALL | | 3898K| | 1656 (0)| 00:00:01 | 1 | 75 | Q1,01 | PCWC | |
|* 22 | INDEX RANGE SCAN | FTR_DT_IX1 | 3898K| | 1656 (0)| 00:00:01 | 1 | 75 | Q1,01 | PCWP | |
|* 23 | TABLE ACCESS BY LOCAL INDEX ROWID| FTR_DT | 276 | 12144 | 50300 (0)| 00:00:01 | 1 | 1 | Q1,01 | PCWP | |
| 24 | PX RECEIVE | | 7344K| 308M| 83875 (1)| 00:00:02 | | | Q1,03 | PCWP | |
| 25 | PX SEND HASH | :TQ10002 | 7344K| 308M| 83875 (1)| 00:00:02 | | | Q1,02 | P->P | HASH |
| 26 | PX BLOCK ITERATOR | | 7344K| 308M| 83875 (1)| 00:00:02 | | | Q1,02 | PCWC | |
|* 27 | TABLE ACCESS STORAGE FULL | DTL_HIST_DT | 7344K| 308M| 83875 (1)| 00:00:02 | | | Q1,02 | PCWP | |
| 28 | PX RECEIVE | | 108K| 3376K| 275 (0)| 00:00:01 | | | Q1,05 | PCWP | |
| 29 | PX SEND HASH | :TQ10004 | 108K| 3376K| 275 (0)| 00:00:01 | | | Q1,04 | P->P | HASH |
| 30 | PX BLOCK ITERATOR | | 108K| 3376K| 275 (0)| 00:00:01 | | | Q1,04 | PCWC | |
|* 31 | TABLE ACCESS STORAGE FULL | POINT_T | 108K| 3376K| 275 (0)| 00:00:01 | | | Q1,04 | PCWP | |
Predicate Information (identified by operation id):
---------------------------------------------------
7 - access("C"."CODE"="AP"."CODE"(+) AND "C"."POINT_ID"="AP"."POINT_ID"(+))
10 - access("CF"."P_ID"="C"."WTN"(+))
19 - filter(LEVEL<=1)
22 - access("CF"."DATE"<=INTERNAL_FUNCTION("D"."MONTH_END"))
23 - filter(UPPER("CF"."PLAN") LIKE '%DV%' AND ("CF"."FT_CODE"='7370' OR "CF"."FT_CODE"='7371' OR "CF"."FT_CODE"='7372' OR
"CF"."FT_CODE"='7373' OR "CF"."FT_CODE"='7374' OR "CF"."FT_CODE"='7380' OR "CF"."FT_CODE"='7380C' OR "CF"."FT_CODE"='7381' OR
"CF"."FT_CODE"='7381C' OR "CF"."FT_CODE"='7382' OR "CF"."FT_CODE"='7382C' OR "CF"."FT_CODE"='7383' OR "CF"."FT_CODE"='7384' OR
"CF"."FT_CODE"='7409' OR "CF"."FT_CODE"='7409C' OR "CF"."FT_CODE"='7410' OR "CF"."FT_CODE"='7410C' OR "CF"."FT_CODE"='TRKDV') AND
"CF"."EXP_DATE">=INTERNAL_FUNCTION("D"."MONTH_END"))
27 - storage("C"."EXP_DATE"(+)>=TRUNC(SYSDATE#!,'fmmm')-1 AND "C"."DATE"(+)<=TRUNC(SYSDATE#!,'fmmm')-1)
filter("C"."EXP_DATE"(+)>=TRUNC(SYSDATE#!,'fmmm')-1 AND "C"."DATE"(+)<=TRUNC(SYSDATE#!,'fmmm')-1)
31 - storage("AP"."EXP_DATE"(+)>=TRUNC(SYSDATE#!,'fmmm')-1 AND "AP"."DATE"(+)<=TRUNC(SYSDATE#!,'fmmm')-1)
filter("AP"."EXP_DATE"(+)>=TRUNC(SYSDATE#!,'fmmm')-1 AND "AP"."DATE"(+)<=TRUNC(SYSDATE#!,'fmmm')-1)
Note
-----
- dynamic sampling used for this statement (level=6)
- automatic DOP: Computed Degree of Parallelism is 8
Edit to add explain plan for faster query:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | TQ |IN-OUT| PQ Distrib |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 278 | 33360 | 622K (1)| 00:00:11 | | | | | |
| 1 | PX COORDINATOR | | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10005 | 278 | 33360 | 622K (1)| 00:00:11 | | | Q1,05 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | 278 | 33360 | 622K (1)| 00:00:11 | | | Q1,05 | PCWP | |
| 4 | PX RECEIVE | | 4034 | 472K| 622K (1)| 00:00:11 | | | Q1,05 | PCWP | |
| 5 | PX SEND HASH | :TQ10004 | 4034 | 472K| 622K (1)| 00:00:11 | | | Q1,04 | P->P | HASH |
|* 6 | HASH JOIN OUTER BUFFERED | | 4034 | 472K| 622K (1)| 00:00:11 | | | Q1,04 | PCWP | |
| 7 | PX RECEIVE | | 4034 | 346K| 621K (1)| 00:00:11 | | | Q1,04 | PCWP | |
| 8 | PX SEND HASH | :TQ10002 | 4034 | 346K| 621K (1)| 00:00:11 | | | Q1,02 | P->P | HASH |
|* 9 | HASH JOIN OUTER BUFFERED | | 4034 | 346K| 621K (1)| 00:00:11 | | | Q1,02 | PCWP | |
| 10 | PX RECEIVE | | 2140 | 94160 | 538K (1)| 00:00:09 | | | Q1,02 | PCWP | |
| 11 | PX SEND HASH | :TQ10000 | 2140 | 94160 | 538K (1)| 00:00:09 | | | Q1,00 | P->P | HASH |
| 12 | PX BLOCK ITERATOR | | 2140 | 94160 | 538K (1)| 00:00:09 | 1 | 75 | Q1,00 | PCWC | |
|* 13 | TABLE ACCESS STORAGE FULL| FTR_DT | 2140 | 94160 | 538K (1)| 00:00:09 | 1 | 75 | Q1,00 | PCWP | |
| 14 | PX RECEIVE | | 7344K| 308M| 83875 (1)| 00:00:02 | | | Q1,02 | PCWP | |
| 15 | PX SEND HASH | :TQ10001 | 7344K| 308M| 83875 (1)| 00:00:02 | | | Q1,01 | P->P | HASH |
| 16 | PX BLOCK ITERATOR | | 7344K| 308M| 83875 (1)| 00:00:02 | | | Q1,01 | PCWC | |
|* 17 | TABLE ACCESS STORAGE FULL| DTL_HIST_DT | 7344K| 308M| 83875 (1)| 00:00:02 | | | Q1,01 | PCWP | |
| 18 | PX RECEIVE | | 108K| 3376K| 275 (0)| 00:00:01 | | | Q1,04 | PCWP | |
| 19 | PX SEND HASH | :TQ10003 | 108K| 3376K| 275 (0)| 00:00:01 | | | Q1,03 | P->P | HASH |
| 20 | PX BLOCK ITERATOR | | 108K| 3376K| 275 (0)| 00:00:01 | | | Q1,03 | PCWC | |
|* 21 | TABLE ACCESS STORAGE FULL | POINT_T | 108K| 3376K| 275 (0)| 00:00:01 | | | Q1,03 | PCWP | |
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("C"."CODE"="AP"."CODE"(+) AND "C"."POINT_ID"="AP"."POINT_ID"(+))
9 - access("CF"."P_ID"="C"."WTN"(+))
13 - storage(UPPER("CF"."PLAN") LIKE '%DV%' AND ("CF"."FT_CODE"='7370' OR "CF"."FT_CODE"='7371' OR "CF"."FT_CODE"='7372' OR
"CF"."FT_CODE"='7373' OR "CF"."FT_CODE"='7374' OR "CF"."FT_CODE"='7380' OR "CF"."FT_CODE"='7380C' OR "CF"."FT_CODE"='7381' OR
"CF"."FT_CODE"='7381C' OR "CF"."FT_CODE"='7382' OR "CF"."FT_CODE"='7382C' OR "CF"."FT_CODE"='7383' OR "CF"."FT_CODE"='7384'
OR "CF"."FT_CODE"='7409' OR "CF"."FT_CODE"='7409C' OR "CF"."FT_CODE"='7410' OR "CF"."FT_CODE"='7410C' OR
"CF"."FT_CODE"='TRKDV') AND "CF"."EXP_DATE">=TRUNC(SYSDATE#!,'fmmm')-1 AND "CF"."DATE"<=TRUNC(SYSDATE#!,'fmmm')-1)
filter(UPPER("CF"."PLAN") LIKE '%DV%' AND ("CF"."FT_CODE"='7370' OR "CF"."FT_CODE"='7371' OR "CF"."FT_CODE"='7372' OR
"CF"."FT_CODE"='7373' OR "CF"."FT_CODE"='7374' OR "CF"."FT_CODE"='7380' OR "CF"."FT_CODE"='7380C' OR "CF"."FT_CODE"='7381' OR
"CF"."FT_CODE"='7381C' OR "CF"."FT_CODE"='7382' OR "CF"."FT_CODE"='7382C' OR "CF"."FT_CODE"='7383' OR "CF"."FT_CODE"='7384'
OR "CF"."FT_CODE"='7409' OR "CF"."FT_CODE"='7409C' OR "CF"."FT_CODE"='7410' OR "CF"."FT_CODE"='7410C' OR
"CF"."FT_CODE"='TRKDV') AND "CF"."EXP_DATE">=TRUNC(SYSDATE#!,'fmmm')-1 AND "CF"."DATE"<=TRUNC(SYSDATE#!,'fmmm')-1)
17 - storage("C"."EXP_DATE"(+)>=TRUNC(SYSDATE#!,'fmmm')-1 AND "C"."DATE"(+)<=TRUNC(SYSDATE#!,'fmmm')-1)
filter("C"."EXP_DATE"(+)>=TRUNC(SYSDATE#!,'fmmm')-1 AND "C"."DATE"(+)<=TRUNC(SYSDATE#!,'fmmm')-1)
21 - storage("AP"."EXP_DATE"(+)>=TRUNC(SYSDATE#!,'fmmm')-1 AND "AP"."DATE"(+)<=TRUNC(SYSDATE#!,'fmmm')-1)
filter("AP"."EXP_DATE"(+)>=TRUNC(SYSDATE#!,'fmmm')-1 AND "AP"."DATE"(+)<=TRUNC(SYSDATE#!,'fmmm')-1)
Note
-----
- dynamic sampling used for this statement (level=6)
- automatic DOP: Computed Degree of Parallelism is 8
In first query Oracle is doing an index range scan on a large table and retrieving huge amounts of data on the first pass with access("CF"."DATE"<=INTERNAL_FUNCTION("D"."MONTH_END")). You can work around it by rewriting your select to be more like your fast one. It would be something like this -
select t.code, trunc(t.exp_date, 'MM') - 1 month_end, count(*)
from device t
where t.date < :report_period_end
and t.exp_date > :report_period_start
group by t.code, trunc(t.exp_date,'MM') - 1;
Also note that there are several potential problems with your original slow query:
A row where t.date and t.exp_date is more than 2 months apart will be counted multiple times.
Rows where t.date and t.exp_date has the same month will not be counted at all
You are comparing your dates to e.g. 2013.10.30 00:00:00. Results may be incorrect if your dates contain time data.