We have a procedure that uses a huge SQL Query to retrieve information, then insert it into a another table XX_REP_TABLE. The SQL query is below:
SELECT
xx_det.ledger_id,
<< ... more where clauses ... >>
nvl(xx_line.tax_calculation_formula, 'STANDARD_TC') tax_line_user_attribute14,
CASE
WHEN COUNT(*) OVER(PARTITION BY xxx_rcpt_line.accounting_class_code, xxx_rcpt_dist.source_distribution_id_num_1, xxx_rcpt_dist.
event_id) = 1 THEN
NULL
WHEN ( ( xxx_rcpt_line.overridden_code_combination_id IS NULL
AND xxx_rcpt_line.override_reason IS NOT NULL )
OR ( EXISTS (
SELECT
'Reversal of original due to override exists'
FROM
xxx_ae_lines xal2,
xxx_distribution_links xdl2
WHERE
xdl2.application_id = 999
AND xal2.application_id = 999
AND xal2.ae_header_id = xdl2.ae_header_id
AND xal2.ae_line_num = xdl2.ae_line_num
AND xal2.overridden_code_combination_id IS NULL
AND xal2.override_reason IS NOT NULL
AND xdl2.source_distribution_type = 'xx_DISTRIBUTIONS_ALL'
AND xal2.ledger_id = xxx_rcpt_line.ledger_id
AND xdl2.source_distribution_id_num_1 = xxx_rcpt_dist.source_distribution_id_num_1
AND xdl2.ref_ae_header_id = xxx_rcpt_dist.ae_header_id
AND xdl2.ref_ae_line_num = xxx_rcpt_dist.ae_line_num
) ) ) THEN
'DEL'
ELSE
NULL
END tax_line_user_attribute15
<< ... more where clauses ... >>
FROM
xx_lines_det_factors xx_det,
xx_lines xx_line,
xx_exemptions xx_ex,
xx_taxes_b xx_tax,
xx_accounts xx_accounts,
xx_rates_vl xx_rate,
xxx_events xxx_event,
xxx_ae_headers xxx_head,
xxx_ae_lines xxx_line,
xxx_acct_class_assgns acs,
xxx_assignment_defns_b asd,
xxx_distribution_links xxx_dist,
xx_receivable_applications_all ara,
xxx_events xxx_rcpt_event,
xxx_ae_headers xxx_rcpt_head,
xxx_ae_lines xxx_rcpt_line,
xxx_distribution_links xxx_rcpt_dist,
xx_distributions_all ardist,
xx_cust_trx_line_gl_dist_all trx_dist,
xx_customer_trx_lines_all lines
WHERE
xx_det.tax_reporting_flag = 'Y'
<< ... more where clauses ... >>
AND 1 = 1;
The Explain plan is below:
---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | exeOrd| Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | 66 | SELECT STATEMENT | | | | | 283K(100)| |
| 1 | 65 | NESTED LOOPS SEMI | | 1 | 319 | | 7 (0)| 00:00:01 |
| 2 | 62 | TABLE ACCESS BY INDEX ROWID BATCHED | xxx_distribution_links | 1 | 50 | | 5 (0)| 00:00:01 |
| 3 | 61 | INDEX RANGE SCAN | xxx_distribution_links_N1 | 2 | | | 4 (0)| 00:00:01 |
| 4 | 64 | TABLE ACCESS BY INDEX ROWID | xxx_ae_lines | 1 | 269 | | 2 (0)| 00:00:01 |
| 5 | 63 | INDEX UNIQUE SCAN | xxx_ae_lines_U1 | 1 | | | 1 (0)| 00:00:01 |
| 6 | 60 | WINDOW SORT | | 1 | 2792 | | 283K (1)| 00:00:12 |
| 7 | 59 | FILTER | | | | | | |
| 8 | 58 | NESTED LOOPS OUTER | | 1 | 2792 | | 283K (1)| 00:00:12 |
| 9 | 56 | NESTED LOOPS | | 1 | 2753 | | 283K (1)| 00:00:12 |
| 10 | 53 | NESTED LOOPS | | 1 | 2743 | | 283K (1)| 00:00:12 |
| 11 | 50 | NESTED LOOPS | | 1 | 2723 | | 283K (1)| 00:00:12 |
| 12 | 47 | NESTED LOOPS | | 1 | 2696 | | 283K (1)| 00:00:12 |
| 13 | 44 | NESTED LOOPS | | 1 | 2654 | | 283K (1)| 00:00:12 |
| 14 | 41 | HASH JOIN | | 1 | 2630 | | 283K (1)| 00:00:12 |
| 15 | 39 | NESTED LOOPS | | 1 | 2585 | | 232K (1)| 00:00:10 |
| 16 | 36 | NESTED LOOPS | | 1 | 2493 | | 232K (1)| 00:00:10 |
| 17 | 33 | NESTED LOOPS | | 15 | 36750 | | 232K (1)| 00:00:10 |
| 18 | 30 | HASH JOIN | | 2455 | 3735K| | 225K (1)| 00:00:09 |
| 19 | 1 | TABLE ACCESS STORAGE FULL | xx_rates_tl | 82 | 8938 | | 5 (0)| 00:00:01 |
| 20 | 29 | HASH JOIN | | 2455 | 3473K| | 225K (1)| 00:00:09 |
| 21 | 2 | TABLE ACCESS STORAGE FULL | xx_rates_b | 82 | 6970 | | 3 (0)| 00:00:01 |
| 22 | 28 | HASH JOIN | | 2455 | 3270K| | 225K (1)| 00:00:09 |
| 23 | 3 | TABLE ACCESS STORAGE FULL | xx_rates_b | 21 | 546 | | 5 (0)| 00:00:01 |
| 24 | 27 | NESTED LOOPS | | 2455 | 3207K| | 225K (1)| 00:00:09 |
| 25 | 25 | NESTED LOOPS | | 9516 | 3207K| | 225K (1)| 00:00:09 |
| 26 | 23 | HASH JOIN | | 2379 | 1119K| 8072K| 218K (1)| 00:00:09 |
| 27 | 20 | JOIN FILTER CREATE | :BF0000 | 2379 | 1119K| | 218K (1)| 00:00:09 |
| 28 | 19 | HASH JOIN | | 18159 | 7855K| 7680K| 190K (1)| 00:00:08 |
| 29 | 16 | JOIN FILTER CREATE | :BF0001 | 18159 | 7855K| | 190K (1)| 00:00:08 |
| 30 | 15 | HASH JOIN | | 18159 | 7465K| 7112K| 168K (1)| 00:00:07 |
| 31 | 12 | JOIN FILTER CREATE | :BF0002 | 18159 | 6898K| | 115K (1)| 00:00:05 |
| 32 | 11 | MERGE JOIN CARTESIAN | | 18159 | 6898K| | 115K (1)| 00:00:05 |
| 33 | 7 | NESTED LOOPS | | 1 | 120 | | 2 (0)| 00:00:01 |
| 34 | 5 | TABLE ACCESS BY INDEX ROWID | xxx_assignment_defns_b | 1 | 53 | | 2 (0)| 00:00:01 |
| 35 | 4 | INDEX SKIP SCAN | xxx_assignment_defns_b_U1 | 1 | | | 1 (0)| 00:00:01 |
| 36 | 6 | INDEX UNIQUE SCAN | xxx_ACCT_CLASS_ASSGNS_U1 | 1 | 67 | | 0 (0)| |
| 37 | 10 | BUFFER SORT | | 329K| 84M| | 115K (1)| 00:00:05 |
| 38 | 9 | TABLE ACCESS BY INDEX ROWID BATCHED| xxx_ae_lines | 329K| 84M| | 115K (1)| 00:00:05 |
| 39 | 8 | INDEX RANGE SCAN | xxx_ae_lines_N2 | 2084K| | | 6741 (1)| 00:00:01 |
| 40 | 14 | JOIN FILTER USE | :BF0002 | 844K| 25M| | 50709 (1)| 00:00:02 |
| 41 | 13 | TABLE ACCESS STORAGE FULL | xxx_ae_headers | 844K| 25M| | 50709 (1)| 00:00:02 |
| 42 | 18 | JOIN FILTER USE | :BF0001 | 2526K| 53M| | 18048 (1)| 00:00:01 |
| 43 | 17 | TABLE ACCESS STORAGE FULL | xxx_events | 2526K| 53M| | 18048 (1)| 00:00:01 |
| 44 | 22 | JOIN FILTER USE | :BF0000 | 319K| 11M| | 27552 (1)| 00:00:02 |
| 45 | 21 | TABLE ACCESS STORAGE FULL | xx_receivable_applications_all | 319K| 11M| | 27552 (1)| 00:00:02 |
| 46 | 24 | INDEX RANGE SCAN | xx_LINES_N4 | 4 | | | 2 (0)| 00:00:01 |
| 47 | 26 | TABLE ACCESS BY INDEX ROWID | xx_lines | 1 | 856 | | 3 (0)| 00:00:01 |
| 48 | 32 | TABLE ACCESS BY INDEX ROWID BATCHED | xx_lines_det_factors | 1 | 892 | | 3 (0)| 00:00:01 |
| 49 | 31 | INDEX RANGE SCAN | xx_LINES_DET_FACTORS_N2 | 3 | | | 2 (0)| 00:00:01 |
| 50 | 35 | TABLE ACCESS BY INDEX ROWID BATCHED | xx_distributions_all | 1 | 43 | | 3 (0)| 00:00:01 |
| 51 | 34 | INDEX RANGE SCAN | xx_DISTRIBUTIONS_N1 | 1 | | | 2 (0)| 00:00:01 |
| 52 | 38 | TABLE ACCESS BY INDEX ROWID BATCHED | xxx_distribution_links | 1 | 92 | | 3 (0)| 00:00:01 |
| 53 | 37 | INDEX RANGE SCAN | xxx_distribution_links_N3 | 1 | | | 2 (0)| 00:00:01 |
| 54 | 40 | TABLE ACCESS STORAGE FULL | xxx_ae_headers | 26278 | 1154K| | 50711 (1)| 00:00:02 |
| 55 | 43 | TABLE ACCESS BY INDEX ROWID BATCHED | xxx_ae_lines | 1 | 24 | | 3 (0)| 00:00:01 |
| 56 | 42 | INDEX RANGE SCAN | xxx_ae_lines_U1 | 1 | | | 2 (0)| 00:00:01 |
| 57 | 46 | TABLE ACCESS BY INDEX ROWID BATCHED | xxx_distribution_links | 1 | 42 | | 3 (0)| 00:00:01 |
| 58 | 45 | INDEX RANGE SCAN | xxx_distribution_links_N3 | 1 | | | 2 (0)| 00:00:01 |
| 59 | 49 | TABLE ACCESS BY INDEX ROWID | xx_cust_trx_line_gl_dist_all | 1 | 27 | | 2 (0)| 00:00:01 |
| 60 | 48 | INDEX UNIQUE SCAN | xx_CUST_TRX_LINE_GL_DIST_U1 | 1 | | | 1 (0)| 00:00:01 |
| 61 | 52 | TABLE ACCESS BY INDEX ROWID | xx_customer_trx_lines_all | 1 | 20 | | 2 (0)| 00:00:01 |
| 62 | 51 | INDEX UNIQUE SCAN | xx_CUSTOMER_TRX_LINES_U1 | 1 | | | 1 (0)| 00:00:01 |
| 63 | 55 | TABLE ACCESS BY INDEX ROWID BATCHED | xxx_events | 1 | 10 | | 3 (0)| 00:00:01 |
| 64 | 54 | INDEX RANGE SCAN | xxx_EVENTS_U1 | 1 | | | 2 (0)| 00:00:01 |
| 65 | 57 | INDEX UNIQUE SCAN | xx_ACCOUNTS_U2 | 1 | 39 | | 0 (0)| |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Based on some of our analysis, this is caused by a COUNT(*) OVER(PARTITION BY in the SELECTed columns. When i remove that Analytic Function, the explain plan removes the Full Table Scans:
-------------------------------------------------------------------------------------------------------------------------------------------------
| Id | exeOrd| Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time |
-------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | 55 | SELECT STATEMENT | | | | 504K(100)| |
| 1 | 54 | NESTED LOOPS | | 1 | 2537 | 504K (1)| 00:00:20 |
| 2 | 51 | NESTED LOOPS | | 1 | 2517 | 504K (1)| 00:00:20 |
| 3 | 48 | NESTED LOOPS | | 1 | 2490 | 504K (1)| 00:00:20 |
| 4 | 45 | NESTED LOOPS | | 1 | 2448 | 504K (1)| 00:00:20 |
| 5 | 42 | NESTED LOOPS | | 1 | 2422 | 504K (1)| 00:00:20 |
| 6 | 39 | NESTED LOOPS | | 1 | 1523 | 504K (1)| 00:00:20 |
| 7 | 36 | NESTED LOOPS | | 9 | 13383 | 504K (1)| 00:00:20 |
| 8 | 33 | NESTED LOOPS | | 9 | 13293 | 504K (1)| 00:00:20 |
|* 9 | 30 | HASH JOIN | | 392 | 546K| 504K (1)| 00:00:20 |
| 10 | 27 | NESTED LOOPS | | 1 | 1403 | 340K (1)| 00:00:14 |
| 11 | 24 | NESTED LOOPS | | 1 | 1381 | 340K (1)| 00:00:14 |
|* 12 | 21 | HASH JOIN | | 1 | 1271 | 340K (1)| 00:00:14 |
| 13 | 19 | NESTED LOOPS | | 1 | 1186 | 340K (1)| 00:00:14 |
| 14 | 16 | NESTED LOOPS | | 2752 | 857K| 333K (1)| 00:00:14 |
| 15 | 13 | NESTED LOOPS | | 12119 | 3313K| 311K (1)| 00:00:13 |
| 16 | 10 | NESTED LOOPS | | 28044 | 6490K| 254K (1)| 00:00:10 |
| 17 | 7 | NESTED LOOPS | | 22839 | 3234K| 163K (1)| 00:00:07 |
| 18 | 4 | NESTED LOOPS | | 1 | 120 | 2 (0)| 00:00:01 |
|* 19 | 2 | TABLE ACCESS BY INDEX ROWID BATCHED| xla_assignment_defns_b | 1 | 53 | 2 (0)| 00:00:01 |
|* 20 | 1 | INDEX SKIP SCAN | XLA_ASSIGNMENT_DEFNS_B_U1 | 1 | | 1 (0)| 00:00:01 |
|* 21 | 3 | INDEX UNIQUE SCAN | XLA_ACCT_CLASS_ASSGNS_U1 | 1 | 67 | 0 (0)| |
|* 22 | 6 | TABLE ACCESS BY INDEX ROWID BATCHED | xla_ae_lines | 414K| 9M| 163K (1)| 00:00:07 |
|* 23 | 5 | INDEX RANGE SCAN | XLA_AE_LINES_N2 | 2824K| | 9684 (1)| 00:00:01 |
|* 24 | 9 | TABLE ACCESS BY INDEX ROWID BATCHED | xla_distribution_links | 1 | 92 | 4 (0)| 00:00:01 |
|* 25 | 8 | INDEX RANGE SCAN | XLA_DISTRIBUTION_LINKS_N3 | 1 | | 3 (0)| 00:00:01 |
|* 26 | 12 | TABLE ACCESS BY INDEX ROWID | ar_distributions_all | 1 | 43 | 2 (0)| 00:00:01 |
|* 27 | 11 | INDEX UNIQUE SCAN | AR_DISTRIBUTIONS_U2 | 1 | | 1 (0)| 00:00:01 |
|* 28 | 15 | TABLE ACCESS BY INDEX ROWID | ar_receivable_applications_all | 1 | 39 | 2 (0)| 00:00:01 |
|* 29 | 14 | INDEX UNIQUE SCAN | AR_RECEIVABLE_APPLICATIONS_U1 | 1 | | 1 (0)| 00:00:01 |
|* 30 | 18 | TABLE ACCESS BY INDEX ROWID BATCHED | zx_lines | 1 | 867 | 3 (0)| 00:00:01 |
|* 31 | 17 | INDEX RANGE SCAN | ZX_LINES_N4 | 4 | | 2 (0)| 00:00:01 |
| 32 | 20 | TABLE ACCESS STORAGE FULL | zx_rates_b | 1 | 85 | 1 (0)| 00:00:01 |
| 33 | 23 | TABLE ACCESS BY INDEX ROWID | zx_rates_tl | 1 | 110 | 1 (0)| 00:00:01 |
|* 34 | 22 | INDEX UNIQUE SCAN | ZX_RATES_TL_U1 | 1 | | 0 (0)| |
|* 35 | 26 | TABLE ACCESS BY INDEX ROWID BATCHED | xla_events | 1 | 22 | 3 (0)| 00:00:01 |
|* 36 | 25 | INDEX RANGE SCAN | XLA_EVENTS_U1 | 1 | | 2 (0)| 00:00:01 |
|* 37 | 29 | TABLE ACCESS BY INDEX ROWID BATCHED | xla_ae_lines | 414K| 9M| 163K (1)| 00:00:07 |
|* 38 | 28 | INDEX RANGE SCAN | XLA_AE_LINES_N2 | 2824K| | 9685 (1)| 00:00:01 |
|* 39 | 32 | TABLE ACCESS BY INDEX ROWID | xla_ae_headers | 1 | 49 | 2 (0)| 00:00:01 |
|* 40 | 31 | INDEX UNIQUE SCAN | XLA_AE_HEADERS_U1 | 1 | | 1 (0)| 00:00:01 |
|* 41 | 35 | TABLE ACCESS BY INDEX ROWID BATCHED | xla_events | 1 | 10 | 3 (0)| 00:00:01 |
|* 42 | 34 | INDEX RANGE SCAN | XLA_EVENTS_U1 | 1 | | 2 (0)| 00:00:01 |
|* 43 | 38 | TABLE ACCESS BY INDEX ROWID | xla_ae_headers | 1 | 36 | 2 (0)| 00:00:01 |
|* 44 | 37 | INDEX UNIQUE SCAN | XLA_AE_HEADERS_U1 | 1 | | 1 (0)| 00:00:01 |
|* 45 | 41 | TABLE ACCESS BY INDEX ROWID BATCHED | zx_lines_det_factors | 1 | 899 | 3 (0)| 00:00:01 |
|* 46 | 40 | INDEX RANGE SCAN | ZX_LINES_DET_FACTORS_N2 | 3 | | 2 (0)| 00:00:01 |
| 47 | 44 | TABLE ACCESS BY INDEX ROWID | zx_taxes_b | 1 | 26 | 1 (0)| 00:00:01 |
|* 48 | 43 | INDEX UNIQUE SCAN | ZX_TAXES_B_U1 | 1 | | 0 (0)| |
|* 49 | 47 | TABLE ACCESS BY INDEX ROWID BATCHED | xla_distribution_links | 1 | 42 | 4 (0)| 00:00:01 |
|* 50 | 46 | INDEX RANGE SCAN | XLA_DISTRIBUTION_LINKS_N3 | 1 | | 3 (0)| 00:00:01 |
|* 51 | 50 | TABLE ACCESS BY INDEX ROWID | ra_cust_trx_line_gl_dist_all | 1 | 27 | 2 (0)| 00:00:01 |
|* 52 | 49 | INDEX UNIQUE SCAN | RA_CUST_TRX_LINE_GL_DIST_U1 | 1 | | 1 (0)| 00:00:01 |
|* 53 | 53 | TABLE ACCESS BY INDEX ROWID | ra_customer_trx_lines_all | 1 | 20 | 2 (0)| 00:00:01 |
|* 54 | 52 | INDEX UNIQUE SCAN | RA_CUSTOMER_TRX_LINES_U1 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------------------------------------------
I plan to move that Analytic function to a separate Procedure, similar to something like below (not yet the exact procedure):
procedure Identify_duplicates (p_request_id number)
as
cursor cur_duplicate_information (p_request_id number)
is
SELECT
REP_TBL_ID, -- UNIQUE IDENTIFIER
CASE
WHEN COUNT(*) OVER(PARTITION BY xxrtbl.accounting_class_code, xxrtbl.source_distribution_id_num_1, xxrtbl.event_id) = 1 THEN
NULL
WHEN ( ( xxx_rcpt_line.overridden_code_combination_id IS NULL
AND xxx_rcpt_line.override_reason IS NOT NULL )
OR ( EXISTS (
SELECT
'Reversal of original due to override exists'
FROM
xxx_ae_lines xal2,
xxx_distribution_links xdl2
WHERE
xdl2.application_id = 999
AND xal2.application_id = 999
AND xal2.ae_header_id = xdl2.ae_header_id
AND xal2.ae_line_num = xdl2.ae_line_num
AND xal2.overridden_code_combination_id IS NULL
AND xal2.override_reason IS NOT NULL
AND xdl2.source_distribution_type = 'xx_DISTRIBUTIONS_ALL'
AND xal2.ledger_id = xxrtbl.ledger_id
AND xdl2.source_distribution_id_num_1 = xxrtbl.source_distribution_id_num_1
AND xdl2.ref_ae_header_id = xxrtbl.ae_header_id
AND xdl2.ref_ae_line_num = xxrtbl.ae_line_num
) ) ) THEN
'DEL'
ELSE
NULL
END tax_line_user_attribute15
FROM XX_REP_TABLE xxrtbl
WHERE REQ_ID = p_request_id;
type typ_dup_info cur_duplicate_information%type;
rec_dup_info typ_dup_info;
begin
OPEN cur_duplicate_information;
FETCH cur_duplicate_information
BULK COLLECT
INTO rec_dup_info
CLOSE cur_duplicate_information;
forall rec_dup_info.first .. rec_dup_info.last
UPDATE XX_REP_TABLE
SET tax_line_user_attribute15 = rec_dup_info(i).tax_line_user_attribute15
where REP_TBL_ID = REP_TBL_ID(i).REP_TBL_ID;
exception
when others then
dbms_output.put_line('Error in :'||SQLERRM);
raise;
end;
I am curious to find out if this will make any difference.
Will "adding" the two explain plans provide a rough estimate of the total cost?
Note: i cannot run this from our own instances because there is too few records to have an actual impact. This performance issue was from our customer and they have billions of records, which we cannot export or mimic. Hence, I wanted to "theoretically" calculate it first before making the code fix.
This query
SELECT a, b, COUNT(*) OVER (PARTITION BY b)
FROM table
gives similar results to
SELECT t.a, t.b, q.number
FROM table t
JOIN ( SELECT b, COUNT(*) number
FROM table
GROUP BY b
) q ON t.b = q.b
The subquery in the second item can exploit an index on b.
Without seeing your entire query, it's hard to guess how to refactor it to use such a subquery.
And, by the way, as long as you're working on that chunk of code, you should consider bringing it into the 1990s by using explicit JOINs. Instead of this
SELECT ...
FROM t1, t2, t3
WHERE t1.t1_id = t2.t1_id
AND t2.t2_id = t3.t2_id(+)
Use this
SELECT ...
FROM t1
INNER JOIN t2 ON t1.t1_id = t2.t1_id
LEFT JOIN t3 ON t2.t2_id = t3.t2_id
The comma-join syntax was replaced by explicit joins in SQL-92, a generation ago.
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.
I got task to improve existing code / query from my company,
Database version
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
"CORE 10.2.0.4.0 Production"
TNS for IBM/AIX RISC System/6000: Version 10.2.0.4.0 - Productio
NLSRTL Version 10.2.0.4.0 - Production
Here's the problem- when below code is executed, the time taken to finish the job is more than 4 hours, something around 7 to 8 hours.
395 row data within 3 hours 37 minutes
SELECT DISTINCT GROUP_DIST_NUMBER, BEGIN_DATE, PRICE_DROP_DATE
FROM (SELECT DISTINCT
G.GROUP_DIST_NUMBER,
TO_DATE (:B2, 'DD-MON-YYYY') BEGIN_DATE,
TO_DATE (:B2, 'DD-MON-YYYY') PRICE_DROP_DATE
FROM POS_DISTI_GROUP G,
POS_CUST_XREF M,
S_CPT_SEQ_NO C,
PP_STD_PRICE P,
S_CPT_AUDIT A,
RPT_PRODUCT_VALUE_LEVEL L
WHERE G.END_DATE > TO_DATE (:B2, 'DD-MON-YYYY')
AND G.GROUP_DIST_NUMBER = M.DIST_NUMBER
AND M.SG_BILL_TO_CUST_NO = A.BILL_TO_CUST_NO
AND A.START_DATE <= TO_DATE (:B2, 'DD-MON-YYYY')
AND A.END_DATE >= TO_DATE (:B2, 'DD-MON-YYYY')
AND L.PROD_VALUE = P.PROD_VALUE
AND L.PROD_LEVEL = P.PROD_LEVEL
AND C.CPT_PRICE_CODE IN
(SELECT /*+ PRECOMPUTE_SUBQUERY */
DISTINCT C1.CPT_PRICE_CODE
FROM PP_STD_PRICE P1,
S_CPT_PRICE_CODE C1,
S_CPT_SEQ_NO S1
WHERE P1.STDP_ID = :B1
AND C1.CPT_PRICE_CAT LIKE 'NB%'
AND C1.CPT_PRICE_CODE = S1.CPT_PRICE_CODE
AND S1.PRICE_PROTECTABLE = 'Y')
AND C.CPT_PRICE_CODE = P.CUST_PRICE_TYPE
AND P.STDP_ID = :B1
AND A.CUST_PRICE_TYPE = C.CPT_BILL_CODE
AND M.ACTIVE_IND != 'N'
AND (M.CATEGORY_TYPE LIKE 'DIRECT%' OR M.INDIRECT_DISTI = 'Y')
AND TRUNC (M.ARCHIVE_DATE) > TRUNC (SYSDATE)
UNION
SELECT G.GROUP_DIST_NUMBER,
P.BEGIN_DATE,
MIN (INVT.PRICE_DROP_DATE) PRICE_DROP_DATE
FROM POS_DISTI_GROUP G,
POS_CUST_XREF M,
PP_DEBIT_AUTHORIZATION P,
RPT_PRODUCT_VALUE_LEVEL L,
POS_PP_INVENTORY INVT
WHERE G.END_DATE > TO_DATE (:B2, 'DD-MON-YYYY')
AND G.GROUP_DIST_NUMBER = M.DIST_NUMBER
AND M.ACTIVE_IND != 'N'
AND (M.CATEGORY_TYPE LIKE 'DIRECT%' OR M.INDIRECT_DISTI = 'Y')
AND G.DIST_NUMBER = P.DIST_NUMBER
AND L.PROD_VALUE = P.PROD_VALUE
AND L.PROD_LEVEL = P.PROD_LEVEL
AND P.BEGIN_DATE >= TO_DATE (:B2, 'DD-MON-YYYY') - 6
AND P.BEGIN_DATE <= TO_DATE (:B2, 'DD-MON-YYYY')
AND INVT.DIST_NUMBER = G.GROUP_DIST_NUMBER
AND INVT.STMODEL = L.MOD_DESC
AND INVT.PPCF_SHOW_DATE = P.BEGIN_DATE
AND P.PRICE_TYPE = 'I'
AND ( P.POS_PROCESSED_FLAG IS NULL
OR P.POS_PROCESSED_FLAG != 'C')
AND P.POS_PP_FLAG = 'Y'
AND TRUNC (M.ARCHIVE_DATE) > TRUNC (SYSDATE)
GROUP BY G.GROUP_DIST_NUMBER, P.BEGIN_DATE)
ORDER BY GROUP_DIST_NUMBER;
I have no idea how to tune this query statement to improve the performance and make it execute faster
here the EXPLAIN PLAN
--------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 2525 | | 24156 (10)| | |
| 1 | SORT ORDER BY | | 101 | 2525 | | 24156 (10)| | |
| 2 | VIEW | | 101 | 2525 | | 24155 (10)| | |
| 3 | SORT UNIQUE | | 101 | 17691 | | 24155 (75)| | |
| 4 | UNION-ALL | | | | | | | |
|* 5 | HASH JOIN | | 10M| 1680M| | 6446 (5)| | |
|* 6 | TABLE ACCESS FULL | S_CPT_SEQ_NO | 651 | 5208 | | 5 (0)| | |
|* 7 | HASH JOIN | | 2383K| 379M| | 6318 (3)| | |
|* 8 | TABLE ACCESS FULL | POS_DISTI_GROUP | 100 | 1800 | | 5 (0)| | |
|* 9 | HASH JOIN | | 2396K| 340M| 4320K| 6283 (3)| | |
| 10 | VIEW | RPT_PRODUCT_VALUE_LEVEL | 138K| 2697K| | 1905 (3)| | |
| 11 | UNION-ALL | | | | | | | |
|* 12 | HASH JOIN RIGHT OUTER | | 13965 | 627K| | 91 (5)| | |
| 13 | INDEX FULL SCAN | PK_SEAEGO_PRODUCT_HIERARCHY | 298 | 4172 | | 1 (0)| | |
|* 14 | HASH JOIN RIGHT OUTER | | 13965 | 436K| | 89 (4)| | |
| 15 | INDEX FULL SCAN | PK_S_CAP_GROUP | 2 | 8 | | 1 (0)| | |
| 16 | TABLE ACCESS FULL | SMA_STMODEL | 13965 | 381K| | 87 (3)| | |
|* 17 | HASH JOIN RIGHT OUTER | | 14175 | 1065K| | 158 (5)| | |
| 18 | INDEX FAST FULL SCAN | PK_S_FAMILY | 1366 | 5464 | | 2 (0)| | |
|* 19 | HASH JOIN RIGHT OUTER | | 14175 | 1010K| | 156 (5)| | |
| 20 | INDEX FULL SCAN | PK_F_MODPRODMGR | 22 | 88 | | 1 (0)| | |
|* 21 | HASH JOIN | | 14175 | 955K| | 154 (4)| | |
| 22 | TABLE ACCESS FULL | SMA_PRODUCTMODEL | 14132 | 317K| | 62 (2)| | |
|* 23 | HASH JOIN RIGHT OUTER | | 13965 | 627K| | 91 (5)| | |
| 24 | INDEX FULL SCAN | PK_SEAEGO_PRODUCT_HIERARCHY | 298 | 4172 | | 1 (0)| | |
|* 25 | HASH JOIN RIGHT OUTER | | 13965 | 436K| | 89 (4)| | |
| 26 | INDEX FULL SCAN | PK_S_CAP_GROUP | 2 | 8 | | 1 (0)| | |
| 27 | TABLE ACCESS FULL | SMA_STMODEL | 13965 | 381K| | 87 (3)| | |
| 28 | MAT_VIEW ACCESS FULL | RPT_PROD_MV | 109K| 1288K| | 1656 (3)| | |
|* 29 | HASH JOIN | | 141K| 17M| | 3191 (3)| | |
|* 30 | INDEX RANGE SCAN | UK_PP_STD_PRICE_STDP_ID | 4128 | 108K| | 23 (0)| | |
|* 31 | HASH JOIN | | 5341 | 532K| | 3165 (3)| | |
|* 32 | TABLE ACCESS FULL | POS_CUST_XREF | 54 | 2268 | | 25 (4)| | |
|* 33 | HASH JOIN | | 193K| 11M| | 3137 (3)| | |
|* 34 | TABLE ACCESS FULL | S_CPT_AUDIT | 68 | 2108 | | 76 (4)| | |
|* 35 | HASH JOIN | | 745K| 20M| | 3052 (2)| | |
| 36 | TABLE ACCESS FULL | S_CPT_SEQ_NO | 1301 | 16913 | | 5 (0)| | |
| 37 | MERGE JOIN CARTESIAN | | 88205 | 1378K| | 3037 (2)| | |
|* 38 | INDEX RANGE SCAN | UK_PP_STD_PRICE_STDP_ID | 4128 | 20640 | | 23 (0)| | |
| 39 | BUFFER SORT | | 21 | 231 | | 3014 (2)| | |
|* 40 | TABLE ACCESS FULL | S_CPT_PRICE_CODE | 21 | 231 | | 1 (0)| | |
| 41 | HASH GROUP BY | | 1 | 191 | | 16421 (5)| | |
|* 42 | FILTER | | | | | | | |
| 43 | NESTED LOOPS | | 1 | 191 | | 16419 (5)| | |
|* 44 | HASH JOIN | | 7 | 1176 | | 16370 (5)| | |
|* 45 | HASH JOIN | | 74 | 8584 | | 4790 (3)| | |
|* 46 | HASH JOIN | | 60 | 3780 | | 31 (7)| | |
|* 47 | TABLE ACCESS FULL | POS_CUST_XREF | 60 | 2100 | | 25 (4)| | |
|* 48 | TABLE ACCESS FULL | POS_DISTI_GROUP | 100 | 2800 | | 5 (0)| | |
|* 49 | TABLE ACCESS FULL | PP_DEBIT_AUTHORIZATION | 345 | 18285 | | 4759 (3)| | |
| 50 | PARTITION RANGE ALL | | 18192 | 923K| | 11579 (6)| 1 | 33 |
|* 51 | INDEX FAST FULL SCAN | POS_PP_INVENTORY_PK | 18192 | 923K| | 11579 (6)| 1 | 33 |
|* 52 | VIEW | RPT_PRODUCT_VALUE_LEVEL | 1 | 23 | | 7 (0)| | |
| 53 | UNION ALL PUSHED PREDICATE | | | | | | | |
|* 54 | FILTER | | | | | | | |
| 55 | NESTED LOOPS OUTER | | 1 | 46 | | 2 (0)| | |
| 56 | NESTED LOOPS OUTER | | 1 | 42 | | 2 (0)| | |
| 57 | TABLE ACCESS BY INDEX ROWID | SMA_STMODEL | 1 | 28 | | 2 (0)| | |
|* 58 | INDEX UNIQUE SCAN | PK_SMA_STMODEL | 1 | | | 1 (0)| | |
|* 59 | INDEX UNIQUE SCAN | PK_SEAEGO_PRODUCT_HIERARCHY | 298 | 4172 | | 0 (0)| | |
|* 60 | INDEX UNIQUE SCAN | PK_S_CAP_GROUP | 2 | 8 | | 0 (0)| | |
| 61 | NESTED LOOPS OUTER | | 1 | 77 | | 3 (0)| | |
| 62 | NESTED LOOPS OUTER | | 1 | 73 | | 3 (0)| | |
| 63 | NESTED LOOPS OUTER | | 1 | 69 | | 3 (0)| | |
| 64 | NESTED LOOPS OUTER | | 1 | 65 | | 3 (0)| | |
| 65 | NESTED LOOPS | | 1 | 51 | | 3 (0)| | |
|* 66 | TABLE ACCESS BY INDEX ROWID| SMA_PRODUCTMODEL | 1 | 23 | | 2 (0)| | |
|* 67 | INDEX UNIQUE SCAN | PK_SMA_PRODUCTMODEL | 1 | | | 1 (0)| | |
| 68 | TABLE ACCESS BY INDEX ROWID| SMA_STMODEL | 1 | 28 | | 1 (0)| | |
|* 69 | INDEX UNIQUE SCAN | PK_SMA_STMODEL | 1 | | | 0 (0)| | |
|* 70 | INDEX UNIQUE SCAN | PK_SEAEGO_PRODUCT_HIERARCHY | 298 | 4172 | | 0 (0)| | |
|* 71 | INDEX UNIQUE SCAN | PK_S_FAMILY | 1366 | 5464 | | 0 (0)| | |
|* 72 | INDEX UNIQUE SCAN | PK_S_CAP_GROUP | 2 | 8 | | 0 (0)| | |
|* 73 | INDEX UNIQUE SCAN | PK_F_MODPRODMGR | 22 | 88 | | 0 (0)| | |
|* 74 | MAT_VIEW ACCESS BY INDEX ROWID | RPT_PROD_MV | 1 | 24 | | 2 (0)| | |
|* 75 | INDEX UNIQUE SCAN | IDX_RPT_PROD_MV_PROD_NO | 1 | | | 1 (0)| | |
--------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("C1"."CPT_PRICE_CODE"="S1"."CPT_PRICE_CODE")
6 - filter("S1"."PRICE_PROTECTABLE"='Y')
7 - access("G"."GROUP_DIST_NUMBER"="M"."DIST_NUMBER")
8 - filter("G"."END_DATE">TO_DATE(:B2,'DD-MON-YYYY'))
9 - access("L"."PROD_VALUE"="P"."PROD_VALUE" AND "L"."PROD_LEVEL"="P"."PROD_LEVEL")
12 - access("ST"."MARKETING_NAME"="PH"."MARKETING_NAME"(+))
14 - access("ST"."MOD_CAPACITY_FORMATTED"="SCG"."MOD_CAPACITY_FORMATTED"(+))
17 - access("SF"."FAMILY"(+)=SUBSTRB("PM"."MODEL",1,3))
19 - access("PM"."DESIGN_APPLICATION"="DA"."DESIGN_APPLICATION"(+))
21 - access("PM"."MOD_DESC"="ST"."MOD_DESC")
23 - access("ST"."MARKETING_NAME"="PH"."MARKETING_NAME"(+))
25 - access("ST"."MOD_CAPACITY_FORMATTED"="SCG"."MOD_CAPACITY_FORMATTED"(+))
29 - access("C"."CPT_PRICE_CODE"="P"."CUST_PRICE_TYPE")
30 - access("P"."STDP_ID"=TO_NUMBER(:B1))
31 - access("M"."SG_BILL_TO_CUST_NO"="A"."BILL_TO_CUST_NO")
32 - filter("M"."SG_BILL_TO_CUST_NO" IS NOT NULL AND ("M"."INDIRECT_DISTI"='Y' OR "M"."CATEGORY_TYPE" LIKE 'DIRECT%') AND
"M"."ACTIVE_IND"<>'N' AND TRUNC(INTERNAL_FUNCTION("M"."ARCHIVE_DATE"))>TRUNC(SYSDATE#!))
33 - access("A"."CUST_PRICE_TYPE"="C"."CPT_BILL_CODE")
34 - filter("A"."START_DATE"<=TO_DATE(:B2,'DD-MON-YYYY') AND "A"."END_DATE">=TO_DATE(:B2,'DD-MON-YYYY'))
35 - access("C"."CPT_PRICE_CODE"="C1"."CPT_PRICE_CODE")
38 - access("P1"."STDP_ID"=TO_NUMBER(:B1))
40 - filter("C1"."CPT_PRICE_CAT" LIKE 'NB%')
42 - filter(TO_DATE(:B2,'DD-MON-YYYY')-6<=TO_DATE(:B2,'DD-MON-YYYY'))
44 - access("INVT"."DIST_NUMBER"="G"."GROUP_DIST_NUMBER" AND "INVT"."PPCF_SHOW_DATE"="P"."BEGIN_DATE")
45 - access("G"."DIST_NUMBER"="P"."DIST_NUMBER")
46 - access("G"."GROUP_DIST_NUMBER"="M"."DIST_NUMBER")
47 - filter(("M"."INDIRECT_DISTI"='Y' OR "M"."CATEGORY_TYPE" LIKE 'DIRECT%') AND "M"."ACTIVE_IND"<>'N' AND
TRUNC(INTERNAL_FUNCTION("M"."ARCHIVE_DATE"))>TRUNC(SYSDATE#!))
48 - filter("G"."END_DATE">TO_DATE(:B2,'DD-MON-YYYY'))
49 - filter("P"."PRICE_TYPE"='I' AND "P"."POS_PP_FLAG"='Y' AND ("P"."POS_PROCESSED_FLAG"<>'C' OR "P"."POS_PROCESSED_FLAG"
IS NULL) AND "P"."BEGIN_DATE"<=TO_DATE(:B2,'DD-MON-YYYY') AND "P"."BEGIN_DATE">=TO_DATE(:B2,'DD-MON-YYYY')-6)
51 - filter("INVT"."PPCF_SHOW_DATE"<=TO_DATE(:B2,'DD-MON-YYYY') AND "INVT"."PPCF_SHOW_DATE">=TO_DATE(:B2,'DD-MON-YYYY')-6)
52 - filter("L"."PROD_LEVEL"="P"."PROD_LEVEL")
54 - filter("P"."PROD_VALUE"="INVT"."STMODEL")
58 - access("ST"."MOD_DESC"="P"."PROD_VALUE")
59 - access("ST"."MARKETING_NAME"="PH"."MARKETING_NAME"(+))
60 - access("ST"."MOD_CAPACITY_FORMATTED"="SCG"."MOD_CAPACITY_FORMATTED"(+))
66 - filter("PM"."MOD_DESC"="INVT"."STMODEL")
67 - access("PM"."MODEL"="P"."PROD_VALUE")
69 - access("ST"."MOD_DESC"="INVT"."STMODEL")
70 - access("ST"."MARKETING_NAME"="PH"."MARKETING_NAME"(+))
71 - access("SF"."FAMILY"(+)=SUBSTRB("PM"."MODEL",1,3))
72 - access("ST"."MOD_CAPACITY_FORMATTED"="SCG"."MOD_CAPACITY_FORMATTED"(+))
73 - access("PM"."DESIGN_APPLICATION"="DA"."DESIGN_APPLICATION"(+))
74 - filter("MOD_DESC"="INVT"."STMODEL")
75 - access("PROD_NO"="P"."PROD_VALUE")
Note
-----
- 'PLAN_TABLE' is old version
and the statistic of rows count for table
TABLE_Name NUM_ROWS
----------- ---------
POS_DISTI_GROUP 2009
POS_CUST_XREF 2801
S_CPT_SEQ_NO 1301
PP_STD_PRICE 2658450
S_CPT_AUDIT 27200
PP_DEBIT_AUTHORIZATION 1199420
POS_PP_INVENTORY 7276850
PP_STD_PRICE 2658450
S_CPT_PRICE_CODE 192
S_CPT_SEQ_NO 1301
SMA_STMODEL 13965
RPT_PROD_MV 109980
create table statement. CLICK HERE
Table Description. CLICK HERE
Retrieve EXPLAIN PLAN with rerun gather_plan_statistics as #jonearles suggest. CLICK HERE
*link from google doc
The problem
Aggregation is happening too late in the execution plan. Plan IDs 4 and 5 generate 13 billion rows and account for 95% of the execution time. Oracle incorrectly believes the number of rows will be smaller, and that earlier aggregations should be merged together.
Plan IDs 6 through 40 represent the first half of the inline view, before the UNION. That part of the query has two DISTINCTs, yet there are no types of aggregation operations for that part of the execution plan. Oracle incorrectly thinks it's better to join everything first and perform one SORT UNIQUE, instead of performing multiple SORT UNIQUE or HASH GROUP BY and combining the results.
Reproduce the problem
Fully reproducing this problem without a full export is almost impossible. Even though it's only a moderately complicated SQL statement there are thousands of variables involved. The code below only demonstrates how Oracle can incorrectly merge aggregation operations.
First, create two simple tables. Each has 100K rows. TEST1 has numbers from 1 to 100000. TEST2 contains 100000 rows, but only one distinct number. To artificially make a bad plan, statistics are gathered too soon on TEST2. The optimizer thinks that TEST2 only has one row but it really has 100000.
drop table test1 purge;
drop table test2 purge;
create table test1(a number);
create table test2(a number);
insert into test1 select level from dual connect by level <= 100000;
insert into test2 values (1);
commit;
begin
dbms_stats.gather_table_stats(user, 'test1');
dbms_stats.gather_table_stats(user, 'test2');
end;
/
insert into test2 select 1 from dual connect by level <= 100000;
commit;
The sample query below retrieves all distinct TEST1.A where A is also in distinct TEST2.A.
By default, using the artificially bad statistics, Oracle joins the tables first and then performs the HASH GROUP BY and HASH UNIQUE. This is a bad plan, it joins all
100K values from TEST2. It would be better to perform the HASH GROUP BY first and then only join 1 row from that table.
explain plan for
select distinct a from test1 where a in (select a from test2 group by a);
select * from table(dbms_xplan.display(format => 'outline'));
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 79 (2)| 00:00:01 |
| 1 | HASH UNIQUE | | 1 | 8 | 79 (2)| 00:00:01 |
| 2 | HASH GROUP BY | | 1 | 8 | 79 (2)| 00:00:01 |
|* 3 | HASH JOIN | | 1 | 8 | 79 (2)| 00:00:01 |
| 4 | TABLE ACCESS FULL| TEST2 | 1 | 3 | 3 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL| TEST1 | 100K| 488K| 76 (2)| 00:00:01 |
------------------------------------------------------------------------------
Potential Solution #1: Hints
Unfortunately there are no official hints to control when and where sorting and grouping happen. By playing around with the outline format option I was able to find a few potentially helpful hints: USE_HASH_AGGREGATION, OUTLINE_LEAF, and PLACE_DISTINCT. (These hints are really tricky - the reason I used a group by instead of another distinct in my sample is because I had so much trouble with the PLACE_DISTINCT hint!)
Using these undocumented hints can build a better plan. The results from TEST2 go through a HASH GROUP BY right away, as they should. This is similar to the plan that would be produced if the statistics were accurate.
explain plan for
select /*+ USE_HASH_AGGREGATION(#"SEL$5DA710D3") OUTLINE_LEAF(#"SEL$683B0107") */
distinct a from test1 where a in (select a from test2 group by a);
select * from table(dbms_xplan.display(format => 'outline alias'));
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 79 (2)| 00:00:01 |
| 1 | HASH UNIQUE | | 1 | 8 | 79 (2)| 00:00:01 |
|* 2 | HASH JOIN SEMI | | 1 | 8 | 79 (2)| 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 1 | 3 | 3 (0)| 00:00:01 |
| 4 | HASH GROUP BY | | 1 | 3 | 3 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL| TEST2 | 1 | 3 | 3 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL | TEST1 | 100K| 488K| 76 (2)| 00:00:01 |
----------------------------------------------------------------------------------
Potential Solution #2: Force a plan with ROWNUM.
A much simpler and safer version of the above is to use ROWNUM. ROWNUM is a pseudocolumn that represents the order of the rows returned. When there is a ROWNUM Oracle cannot move the distinct and group by because it would affect that order.
Unfortunately, this trick requires extra code and generates extra steps in the plan. Those extra steps are mostly just passing data through and shouldn't slow things done much.
explain plan for
select distinct a from test1 where a in
(
--Extra level only because we only want to project one column.
--It's syntactically required, but the optimizer throws out this inline view.
select a
from
(
--The ROWNUM forces everything in this inline view to happen separately.
select a, rownum
from
(
select a from test2 group by a
)
)
);
select * from table(dbms_xplan.display(format => 'outline alias'));
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 79 (2)| 00:00:01 |
| 1 | HASH UNIQUE | | 1 | 8 | 79 (2)| 00:00:01 |
|* 2 | HASH JOIN SEMI | | 1 | 8 | 79 (2)| 00:00:01 |
| 3 | VIEW | | 1 | 3 | 3 (0)| 00:00:01 |
| 4 | COUNT | | | | | |
| 5 | VIEW | | 1 | 3 | 3 (0)| 00:00:01 |
| 6 | HASH GROUP BY | | 1 | 3 | 3 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL| TEST2 | 1 | 3 | 3 (0)| 00:00:01 |
| 8 | TABLE ACCESS FULL | TEST1 | 100K| 488K| 76 (2)| 00:00:01 |
---------------------------------------------------------------------------------
Potential Solution #3: Fix cardinality estimates and hope for the best.
If the estimated number of rows is accurate the plan is almost always good. When the row estimates are far off, find the first part of the execution plan where the cardinality is wrong. For this plan, it appears to be plan ID 36. E-Rows and A-Rows are off by an order of magnitude:
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | O/1/M |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
...
|* 36 | TABLE ACCESS FULL | POS_CUST_XREF | 1 | 54 | 579 |00:00:00.01 | 131 | 0 | | | |
Step 36 has a complex predicate that involves SYSDATE.
36 - filter(("M"."SG_BILL_TO_CUST_NO" IS NOT NULL AND ("M"."INDIRECT_DISTI"='Y' OR "M"."CATEGORY_TYPE" LIKE 'DIRECT%') AND "M"."ACTIVE_IND"<>'N' AND
TRUNC(INTERNAL_FUNCTION("M"."ARCHIVE_DATE"))>TRUNC(SYSDATE#!)))
Even with up-to-date statistics that condition is going to be difficult to predict. Dynamic sampling may help. Try re-running the query with a top-level hint like this:
SELECT /*+ dynamic_sampling(6) */ ...
Fixing those early discrepancies will usually fix other problems later in the plan. This example is only one possible source of cardinality mismatches. Other tricks may be necessary to improve other cardinality estimates. This can be a very difficult method but it can pay off in multiple ways.
Red Herrings
There are many potential improvements to any moderately complicated SQL statement. There are several good ideas in the comments and answers. But when tuning it is always imperative to focus on what is slowest, not what is easiest to fix. It sounds obvious, but it's a very easy trap to fall into. That's why I asked you to use /*+ gather_plan_statistics*/, and that's why my answer only focuses on the parts of the plan with a large actual time.
For example, in my earlier comment I suggested looking at the NESTED LOOPS where ROWS=1. Now that we have the actual time we know that suggestion is not helpful. (Although in general you should still be skeptical of a plan with large tables but ROWS=1.)
Before rewriting the query, could you please reply with plan and run time for this query?
Follow Up:
Adding Parallel hint
Adding partition clause in select
The precompute_subquery hint will take subquery text out of the subquery section, fire it separately (before running main query) in a recursive call context, fetch the results and pass these to main query "filter" condition as a list of OR conditions. This is called subquery unfolding I think and it's different from the query block unparsing which is used for distributed queries. I've seen it used in OLAP queries.
As this is an undocumented hint, it should not be used by developers! The subquery is actually executed during soft parsing time, thus multiple executions of the same child cursor may potentially return wrong results if resultset of the subquery changes (unless Oracle always forces another full parse of these cursors somehow - in which case you can end up with library cache/shared pool latch contention if misusing this feature). So I removed it and used parallel for huge tables.
Also dont use Order by which overkills the query run time.
SELECT
DISTINCT GROUP_DIST_NUMBER,
BEGIN_DATE,
PRICE_DROP_DATE
FROM
(SELECT /*+ PARALLEL (P,4) PARALLEL (L,4)*/
DISTINCT
G.GROUP_DIST_NUMBER,
TO_DATE ( :B2,
'DD-MON-YYYY' )
BEGIN_DATE,
TO_DATE ( :B2,
'DD-MON-YYYY' )
PRICE_DROP_DATE
FROM
POS_DISTI_GROUP G,
POS_CUST_XREF M,
S_CPT_SEQ_NO C,
PP_STD_PRICE P,
S_CPT_AUDIT A,
RPT_PRODUCT_VALUE_LEVEL L
WHERE
G.END_DATE > TO_DATE ( :B2,
'DD-MON-YYYY' )
AND G.GROUP_DIST_NUMBER = M.DIST_NUMBER
AND M.SG_BILL_TO_CUST_NO = A.BILL_TO_CUST_NO
AND A.START_DATE <= TO_DATE ( :B2,
'DD-MON-YYYY' )
AND A.END_DATE >= TO_DATE ( :B2,
'DD-MON-YYYY' )
AND L.PROD_VALUE = P.PROD_VALUE
AND L.PROD_LEVEL = P.PROD_LEVEL
AND C.CPT_PRICE_CODE IN
(SELECT /*+ PARALLEL (P1,4)*/
DISTINCT C1.CPT_PRICE_CODE
FROM
PP_STD_PRICE P1,
S_CPT_PRICE_CODE C1,
S_CPT_SEQ_NO S1
WHERE
P1.STDP_ID = :B1
AND C1.CPT_PRICE_CAT LIKE 'NB%'
AND C1.CPT_PRICE_CODE = S1.CPT_PRICE_CODE
AND S1.PRICE_PROTECTABLE = 'Y')
AND C.CPT_PRICE_CODE = P.CUST_PRICE_TYPE
AND P.STDP_ID = :B1
AND A.CUST_PRICE_TYPE = C.CPT_BILL_CODE
AND M.ACTIVE_IND != 'N'
AND ( M.CATEGORY_TYPE LIKE 'DIRECT%'
OR M.INDIRECT_DISTI = 'Y' )
AND TRUNC ( M.ARCHIVE_DATE ) > TRUNC ( SYSDATE )
UNION
SELECT /*+ PARALLEL (P,4) PARALLEL (L,4) */
G.GROUP_DIST_NUMBER,
P.BEGIN_DATE,
MIN ( INVT.PRICE_DROP_DATE ) PRICE_DROP_DATE
FROM
POS_DISTI_GROUP G,
POS_CUST_XREF M,
PP_DEBIT_AUTHORIZATION P,
RPT_PRODUCT_VALUE_LEVEL L,
POS_PP_INVENTORY PARTITION ("F2011_Q2") INVT
WHERE
G.END_DATE > TO_DATE ( :B2,
'DD-MON-YYYY' )
AND G.GROUP_DIST_NUMBER = M.DIST_NUMBER
AND M.ACTIVE_IND != 'N'
AND ( M.CATEGORY_TYPE LIKE 'DIRECT%'
OR M.INDIRECT_DISTI = 'Y' )
AND G.DIST_NUMBER = P.DIST_NUMBER
AND L.PROD_VALUE = P.PROD_VALUE
AND L.PROD_LEVEL = P.PROD_LEVEL
AND P.BEGIN_DATE >= TO_DATE ( :B2,
'DD-MON-YYYY' )
- 6
AND P.BEGIN_DATE <= TO_DATE ( :B2,
'DD-MON-YYYY' )
AND INVT.DIST_NUMBER = G.GROUP_DIST_NUMBER
AND INVT.STMODEL = L.MOD_DESC
AND INVT.PPCF_SHOW_DATE = P.BEGIN_DATE
AND P.PRICE_TYPE = 'I'
AND ( P.POS_PROCESSED_FLAG IS NULL
OR P.POS_PROCESSED_FLAG != 'C' )
AND P.POS_PP_FLAG = 'Y'
AND TRUNC ( M.ARCHIVE_DATE ) > TRUNC ( SYSDATE )
GROUP BY
G.GROUP_DIST_NUMBER,
P.BEGIN_DATE);
EXPLAIN PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Pstart| Pstop | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 2525 | 8500 (17)| | | | | |
| 1 | PX COORDINATOR | | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10005 | 101 | 2525 | 8500 (17)| | | Q1,05 | P->S | QC (RAND) |
| 3 | VIEW | | 101 | 2525 | 8500 (17)| | | Q1,05 | PCWP | |
| 4 | SORT UNIQUE | | 101 | 18291 | 8500 (82)| | | Q1,05 | PCWP | |
| 5 | PX RECEIVE | | | | | | | Q1,05 | PCWP | |
| 6 | PX SEND HASH | :TQ10004 | | | | | | Q1,04 | P->P | HASH |
| 7 | BUFFER SORT | | 101 | 2525 | | | | Q1,04 | PCWP | |
| 8 | UNION-ALL | | | | | | | Q1,04 | PCWP | |
| 9 | BUFFER SORT | | | | | | | Q1,04 | PCWC | |
| 10 | PX RECEIVE | | | | | | | Q1,04 | PCWP | |
| 11 | PX SEND ROUND-ROBIN | :TQ10001 | | | | | | | S->P | RND-ROBIN |
| 12 | MERGE JOIN CARTESIAN | | 10M| 1737M| 1635 (5)| | | | | |
|* 13 | HASH JOIN | | 2439 | 419K| 322 (3)| | | | | |
|* 14 | TABLE ACCESS FULL | POS_DISTI_GROUP | 100 | 1800 | 5 (0)| | | | | |
|* 15 | HASH JOIN | | 2452 | 378K| 317 (3)| | | | | |
|* 16 | TABLE ACCESS FULL | S_CPT_SEQ_NO | 651 | 5208 | 5 (0)| | | | | |
| 17 | NESTED LOOPS | | 580 | 87000 | 311 (2)| | | | | |
| 18 | NESTED LOOPS | | 34 | 4658 | 131 (4)| | | | | |
|* 19 | HASH JOIN | | 1 | 97 | 109 (5)| | | | | |
|* 20 | HASH JOIN | | 9 | 774 | 107 (5)| | | | | |
|* 21 | HASH JOIN | | 2 | 146 | 101 (4)| | | | | |
|* 22 | TABLE ACCESS FULL | POS_CUST_XREF | 54 | 2268 | 25 (4)| | | | | |
|* 23 | TABLE ACCESS FULL | S_CPT_AUDIT | 68 | 2108 | 76 (4)| | | | | |
| 24 | TABLE ACCESS FULL | S_CPT_SEQ_NO | 1301 | 16913 | 5 (0)| | | | | |
|* 25 | TABLE ACCESS FULL | S_CPT_PRICE_CODE | 21 | 231 | 2 (0)| | | | | |
|* 26 | INDEX RANGE SCAN | UK_PP_STD_PRICE_STDP_ID | 26 | 1040 | 22 (0)| | | | | |
|* 27 | VIEW | RPT_PRODUCT_VALUE_LEVEL | 1 | 13 | 5 (0)| | | | | |
| 28 | UNION ALL PUSHED PREDICATE | | | | | | | | | |
| 29 | NESTED LOOPS OUTER | | 1 | 46 | 2 (0)| | | | | |
| 30 | NESTED LOOPS OUTER | | 1 | 42 | 2 (0)| | | | | |
| 31 | TABLE ACCESS BY INDEX ROWID | SMA_STMODEL | 1 | 28 | 2 (0)| | | | | |
|* 32 | INDEX UNIQUE SCAN | PK_SMA_STMODEL | 1 | | 1 (0)| | | | | |
|* 33 | INDEX UNIQUE SCAN | PK_SEAEGO_PRODUCT_HIERARCHY | 298 | 4172 | 0 (0)| | | | | |
|* 34 | INDEX UNIQUE SCAN | PK_S_CAP_GROUP | 2 | 8 | 0 (0)| | | | | |
| 35 | NESTED LOOPS OUTER | | 1 | 77 | 2 (0)| | | | | |
| 36 | NESTED LOOPS OUTER | | 1 | 73 | 2 (0)| | | | | |
| 37 | NESTED LOOPS | | 1 | 59 | 2 (0)| | | | | |
| 38 | NESTED LOOPS OUTER | | 1 | 31 | 2 (0)| | | | | |
| 39 | NESTED LOOPS OUTER | | 1 | 27 | 2 (0)| | | | | |
| 40 | TABLE ACCESS BY INDEX ROWID| SMA_PRODUCTMODEL | 1 | 23 | 2 (0)| | | | | |
|* 41 | INDEX UNIQUE SCAN | PK_SMA_PRODUCTMODEL | 1 | | 1 (0)| | | | | |
|* 42 | INDEX UNIQUE SCAN | PK_S_FAMILY | 1366 | 5464 | 0 (0)| | | | | |
|* 43 | INDEX UNIQUE SCAN | PK_F_MODPRODMGR | 22 | 88 | 0 (0)| | | | | |
| 44 | TABLE ACCESS BY INDEX ROWID | SMA_STMODEL | 13965 | 381K| 1 (0)| | | | | |
|* 45 | INDEX UNIQUE SCAN | PK_SMA_STMODEL | 1 | | 0 (0)| | | | | |
|* 46 | INDEX UNIQUE SCAN | PK_SEAEGO_PRODUCT_HIERARCHY | 298 | 4172 | 0 (0)| | | | | |
|* 47 | INDEX UNIQUE SCAN | PK_S_CAP_GROUP | 2 | 8 | 0 (0)| | | | | |
|* 48 | INDEX UNIQUE SCAN | IDX_RPT_PROD_MV_PROD_NO | 1 | 12 | 1 (0)| | | | | |
| 49 | BUFFER SORT | | 4128 | 20640 | 1629 (5)| | | | | |
|* 50 | INDEX RANGE SCAN | UK_PP_STD_PRICE_STDP_ID | 4128 | 20640 | 23 (0)| | | | | |
| 51 | HASH GROUP BY | | 1 | 191 | 5578 (2)| | | Q1,04 | PCWP | |
| 52 | PX RECEIVE | | 1 | 191 | 5578 (2)| | | Q1,04 | PCWP | |
| 53 | PX SEND HASH | :TQ10003 | 1 | 191 | 5578 (2)| | | Q1,03 | P->P | HASH |
| 54 | HASH GROUP BY | | 1 | 191 | 5578 (2)| | | Q1,03 | PCWP | |
|* 55 | FILTER | | | | | | | Q1,03 | PCWC | |
| 56 | NESTED LOOPS | | 1 | 191 | 5575 (2)| | | Q1,03 | PCWP | |
| 57 | NESTED LOOPS | | 7 | 1176 | 5562 (2)| | | Q1,03 | PCWP | |
|* 58 | HASH JOIN | | 74 | 8584 | 1347 (3)| | | Q1,03 | PCWP | |
| 59 | BUFFER SORT | | | | | | | Q1,03 | PCWC | |
| 60 | PX RECEIVE | | 60 | 3780 | 31 (7)| | | Q1,03 | PCWP | |
| 61 | PX SEND HASH | :TQ10000 | 60 | 3780 | 31 (7)| | | | S->P | HASH |
|* 62 | HASH JOIN | | 60 | 3780 | 31 (7)| | | | | |
|* 63 | TABLE ACCESS FULL | POS_CUST_XREF | 60 | 2100 | 25 (4)| | | | | |
|* 64 | TABLE ACCESS FULL | POS_DISTI_GROUP | 100 | 2800 | 5 (0)| | | | | |
| 65 | PX RECEIVE | | 345 | 18285 | 1316 (2)| | | Q1,03 | PCWP | |
| 66 | PX SEND HASH | :TQ10002 | 345 | 18285 | 1316 (2)| | | Q1,02 | P->P | HASH |
| 67 | PX BLOCK ITERATOR | | 345 | 18285 | 1316 (2)| | | Q1,02 | PCWC | |
|* 68 | TABLE ACCESS FULL | PP_DEBIT_AUTHORIZATION | 345 | 18285 | 1316 (2)| | | Q1,02 | PCWP | |
| 69 | PARTITION RANGE ALL | | 1 | 52 | 205 (1)| 1 | 33 | Q1,03 | PCWP | |
|* 70 | INDEX RANGE SCAN | POS_PP_INVENTORY_PK | 1 | 52 | 205 (1)| 1 | 33 | Q1,03 | PCWP | |
|* 71 | VIEW | RPT_PRODUCT_VALUE_LEVEL | 1 | 23 | 7 (0)| | | Q1,03 | PCWP | |
| 72 | UNION ALL PUSHED PREDICATE | | | | | | | Q1,03 | PCWP | |
|* 73 | FILTER | | | | | | | Q1,03 | PCWP | |
| 74 | NESTED LOOPS OUTER | | 1 | 46 | 2 (0)| | | Q1,03 | PCWP | |
| 75 | NESTED LOOPS OUTER | | 1 | 42 | 2 (0)| | | Q1,03 | PCWP | |
| 76 | TABLE ACCESS BY INDEX ROWID | SMA_STMODEL | 1 | 28 | 2 (0)| | | Q1,03 | PCWP | |
|* 77 | INDEX UNIQUE SCAN | PK_SMA_STMODEL | 1 | | 1 (0)| | | Q1,03 | PCWP | |
|* 78 | INDEX UNIQUE SCAN | PK_SEAEGO_PRODUCT_HIERARCHY | 298 | 4172 | 0 (0)| | | Q1,03 | PCWP | |
|* 79 | INDEX UNIQUE SCAN | PK_S_CAP_GROUP | 2 | 8 | 0 (0)| | | Q1,03 | PCWP | |
| 80 | NESTED LOOPS OUTER | | 1 | 77 | 3 (0)| | | Q1,03 | PCWP | |
| 81 | NESTED LOOPS OUTER | | 1 | 73 | 3 (0)| | | Q1,03 | PCWP | |
| 82 | NESTED LOOPS OUTER | | 1 | 69 | 3 (0)| | | Q1,03 | PCWP | |
| 83 | NESTED LOOPS OUTER | | 1 | 65 | 3 (0)| | | Q1,03 | PCWP | |
| 84 | NESTED LOOPS | | 1 | 51 | 3 (0)| | | Q1,03 | PCWP | |
|* 85 | TABLE ACCESS BY INDEX ROWID | SMA_PRODUCTMODEL | 1 | 23 | 2 (0)| | | Q1,03 | PCWP | |
|* 86 | INDEX UNIQUE SCAN | PK_SMA_PRODUCTMODEL | 1 | | 1 (0)| | | Q1,03 | PCWP | |
| 87 | TABLE ACCESS BY INDEX ROWID | SMA_STMODEL | 1 | 28 | 1 (0)| | | Q1,03 | PCWP | |
|* 88 | INDEX UNIQUE SCAN | PK_SMA_STMODEL | 1 | | 0 (0)| | | Q1,03 | PCWP | |
|* 89 | INDEX UNIQUE SCAN | PK_SEAEGO_PRODUCT_HIERARCHY | 298 | 4172 | 0 (0)| | | Q1,03 | PCWP | |
|* 90 | INDEX UNIQUE SCAN | PK_S_FAMILY | 1366 | 5464 | 0 (0)| | | Q1,03 | PCWP | |
|* 91 | INDEX UNIQUE SCAN | PK_S_CAP_GROUP | 2 | 8 | 0 (0)| | | Q1,03 | PCWP | |
|* 92 | INDEX UNIQUE SCAN | PK_F_MODPRODMGR | 22 | 88 | 0 (0)| | | Q1,03 | PCWP | |
|* 93 | MAT_VIEW ACCESS BY INDEX ROWID | RPT_PROD_MV | 1 | 24 | 2 (0)| | | Q1,03 | PCWP | |
|* 94 | INDEX UNIQUE SCAN | IDX_RPT_PROD_MV_PROD_NO | 1 | | 1 (0)| | | Q1,03 | PCWP | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
13 - access("G"."GROUP_DIST_NUMBER"="M"."DIST_NUMBER")
14 - filter("G"."END_DATE">TO_DATE(:B2,'DD-MON-YYYY'))
15 - access("C1"."CPT_PRICE_CODE"="S1"."CPT_PRICE_CODE")
16 - filter("S1"."PRICE_PROTECTABLE"='Y')
19 - access("C"."CPT_PRICE_CODE"="C1"."CPT_PRICE_CODE")
20 - access("A"."CUST_PRICE_TYPE"="C"."CPT_BILL_CODE")
21 - access("M"."SG_BILL_TO_CUST_NO"="A"."BILL_TO_CUST_NO")
22 - filter("M"."SG_BILL_TO_CUST_NO" IS NOT NULL AND ("M"."INDIRECT_DISTI"='Y' OR "M"."CATEGORY_TYPE" LIKE 'DIRECT%') AND "M"."ACTIVE_IND"<>'N' AND
TRUNC(INTERNAL_FUNCTION("M"."ARCHIVE_DATE"))>TRUNC(SYSDATE#!))
23 - filter("A"."START_DATE"<=TO_DATE(:B2,'DD-MON-YYYY') AND "A"."END_DATE">=TO_DATE(:B2,'DD-MON-YYYY'))
25 - filter("C1"."CPT_PRICE_CAT" LIKE 'NB%')
26 - access("P"."STDP_ID"=TO_NUMBER(:B1) AND "C"."CPT_PRICE_CODE"="P"."CUST_PRICE_TYPE")
filter("C"."CPT_PRICE_CODE"="P"."CUST_PRICE_TYPE")
27 - filter("L"."PROD_LEVEL"="P"."PROD_LEVEL")
32 - access("ST"."MOD_DESC"="P"."PROD_VALUE")
33 - access("ST"."MARKETING_NAME"="PH"."MARKETING_NAME"(+))
34 - access("ST"."MOD_CAPACITY_FORMATTED"="SCG"."MOD_CAPACITY_FORMATTED"(+))
41 - access("PM"."MODEL"="P"."PROD_VALUE")
42 - access("SF"."FAMILY"(+)=SUBSTRB("PM"."MODEL",1,3))
43 - access("PM"."DESIGN_APPLICATION"="DA"."DESIGN_APPLICATION"(+))
45 - access("PM"."MOD_DESC"="ST"."MOD_DESC")
46 - access("ST"."MARKETING_NAME"="PH"."MARKETING_NAME"(+))
47 - access("ST"."MOD_CAPACITY_FORMATTED"="SCG"."MOD_CAPACITY_FORMATTED"(+))
48 - access("PROD_NO"="P"."PROD_VALUE")
50 - access("P1"."STDP_ID"=TO_NUMBER(:B1))
55 - filter(TO_DATE(:B2,'DD-MON-YYYY')-6<=TO_DATE(:B2,'DD-MON-YYYY'))
58 - access("G"."DIST_NUMBER"="P"."DIST_NUMBER")
62 - access("G"."GROUP_DIST_NUMBER"="M"."DIST_NUMBER")
63 - filter(("M"."INDIRECT_DISTI"='Y' OR "M"."CATEGORY_TYPE" LIKE 'DIRECT%') AND "M"."ACTIVE_IND"<>'N' AND
TRUNC(INTERNAL_FUNCTION("M"."ARCHIVE_DATE"))>TRUNC(SYSDATE#!))
64 - filter("G"."END_DATE">TO_DATE(:B2,'DD-MON-YYYY'))
68 - filter("P"."PRICE_TYPE"='I' AND "P"."POS_PP_FLAG"='Y' AND ("P"."POS_PROCESSED_FLAG"<>'C' OR "P"."POS_PROCESSED_FLAG" IS NULL) AND
"P"."BEGIN_DATE"<=TO_DATE(:B2,'DD-MON-YYYY') AND "P"."BEGIN_DATE">=TO_DATE(:B2,'DD-MON-YYYY')-6)
70 - access("INVT"."DIST_NUMBER"="G"."GROUP_DIST_NUMBER" AND "INVT"."PPCF_SHOW_DATE"="P"."BEGIN_DATE")
filter("INVT"."PPCF_SHOW_DATE"<=TO_DATE(:B2,'DD-MON-YYYY') AND "INVT"."PPCF_SHOW_DATE">=TO_DATE(:B2,'DD-MON-YYYY')-6 AND
"INVT"."PPCF_SHOW_DATE"="P"."BEGIN_DATE")
71 - filter("L"."PROD_LEVEL"="P"."PROD_LEVEL")
73 - filter("P"."PROD_VALUE"="INVT"."STMODEL")
77 - access("ST"."MOD_DESC"="P"."PROD_VALUE")
78 - access("ST"."MARKETING_NAME"="PH"."MARKETING_NAME"(+))
79 - access("ST"."MOD_CAPACITY_FORMATTED"="SCG"."MOD_CAPACITY_FORMATTED"(+))
85 - filter("PM"."MOD_DESC"="INVT"."STMODEL")
86 - access("PM"."MODEL"="P"."PROD_VALUE")
88 - access("ST"."MOD_DESC"="INVT"."STMODEL")
89 - access("ST"."MARKETING_NAME"="PH"."MARKETING_NAME"(+))
90 - access("SF"."FAMILY"(+)=SUBSTRB("PM"."MODEL",1,3))
91 - access("ST"."MOD_CAPACITY_FORMATTED"="SCG"."MOD_CAPACITY_FORMATTED"(+))
92 - access("PM"."DESIGN_APPLICATION"="DA"."DESIGN_APPLICATION"(+))
93 - filter("MOD_DESC"="INVT"."STMODEL")
94 - access("PROD_NO"="P"."PROD_VALUE")
Note
-----
- 'PLAN_TABLE' is old version
PS:
Did you manage to get Run time? Also I change the query, please test this and let us know the result. Ideally the first query should be faster than yours and the second one (replaced the first) should be better than the first one.Remember to keep them separately with notes on performance.
just guess, but look like your statement not using index on archive_date column
try to use
AND M.ARCHIVE_DATE > TRUNC (SYSDATE) + 1 - 1/24/60/60
instead of
AND TRUNC (M.ARCHIVE_DATE) > TRUNC (SYSDATE)
also you should post all tables description into question
SELECT /*+ PARALLEL (P,4) PARALLEL (L,4)*/
DISTINCT
G.GROUP_DIST_NUMBER,
TO_DATE ( :B2,
'DD-MON-YYYY' )
BEGIN_DATE,
TO_DATE ( :B2,
'DD-MON-YYYY' )
PRICE_DROP_DATE
FROM
POS_DISTI_GROUP G,
POS_CUST_XREF M,
S_CPT_SEQ_NO C,
PP_STD_PRICE P,
S_CPT_AUDIT A,
RPT_PRODUCT_VALUE_LEVEL L
WHERE 1=0 -- switched off
G.END_DATE > TO_DATE ( :B2,
'DD-MON-YYYY' )
AND G.GROUP_DIST_NUMBER = M.DIST_NUMBER
AND M.SG_BILL_TO_CUST_NO = A.BILL_TO_CUST_NO
AND A.START_DATE <= TO_DATE ( :B2,
'DD-MON-YYYY' )
AND A.END_DATE >= TO_DATE ( :B2,
'DD-MON-YYYY' )
AND L.PROD_VALUE = P.PROD_VALUE
AND L.PROD_LEVEL = P.PROD_LEVEL
AND C.CPT_PRICE_CODE IN
(SELECT /*+ PARALLEL (P1,4)*/
DISTINCT C1.CPT_PRICE_CODE
FROM
PP_STD_PRICE P1,
S_CPT_PRICE_CODE C1,
S_CPT_SEQ_NO S1
WHERE
P1.STDP_ID = :B1
AND C1.CPT_PRICE_CAT LIKE 'NB%'
AND C1.CPT_PRICE_CODE = S1.CPT_PRICE_CODE
AND S1.PRICE_PROTECTABLE = 'Y')
AND C.CPT_PRICE_CODE = P.CUST_PRICE_TYPE
AND P.STDP_ID = :B1
AND A.CUST_PRICE_TYPE = C.CPT_BILL_CODE
AND M.ACTIVE_IND != 'N'
AND ( M.CATEGORY_TYPE LIKE 'DIRECT%'
OR M.INDIRECT_DISTI = 'Y' )
AND TRUNC ( M.ARCHIVE_DATE ) > TRUNC ( SYSDATE )
UNION
SELECT /*+ PARALLEL (P,4) PARALLEL (L,4) */
G.GROUP_DIST_NUMBER,
P.BEGIN_DATE,
MIN ( INVT.PRICE_DROP_DATE ) PRICE_DROP_DATE
FROM
POS_DISTI_GROUP G,
POS_CUST_XREF M,
PP_DEBIT_AUTHORIZATION P,
RPT_PRODUCT_VALUE_LEVEL L,
POS_PP_INVENTORY PARTITION ("F2011_Q2") INVT
WHERE 1=0 -- switched off
G.END_DATE > TO_DATE ( :B2,
'DD-MON-YYYY' )
AND G.GROUP_DIST_NUMBER = M.DIST_NUMBER
AND M.ACTIVE_IND != 'N'
AND ( M.CATEGORY_TYPE LIKE 'DIRECT%'
OR M.INDIRECT_DISTI = 'Y' )
AND G.DIST_NUMBER = P.DIST_NUMBER
AND L.PROD_VALUE = P.PROD_VALUE
AND L.PROD_LEVEL = P.PROD_LEVEL
AND P.BEGIN_DATE >= TO_DATE ( :B2,
'DD-MON-YYYY' )
- 6
AND P.BEGIN_DATE <= TO_DATE ( :B2,
'DD-MON-YYYY' )
AND INVT.DIST_NUMBER = G.GROUP_DIST_NUMBER
AND INVT.STMODEL = L.MOD_DESC
AND INVT.PPCF_SHOW_DATE = P.BEGIN_DATE
AND P.PRICE_TYPE = 'I'
AND ( P.POS_PROCESSED_FLAG IS NULL
OR P.POS_PROCESSED_FLAG != 'C' )
AND P.POS_PP_FLAG = 'Y'
AND TRUNC ( M.ARCHIVE_DATE ) > TRUNC ( SYSDATE )
GROUP BY
G.GROUP_DIST_NUMBER,
P.BEGIN_DATE
Result From OP:
After try to switch off and on here there result
1. Switch off 1st where condition
2.Switch off 2nd where condition
3.Switch off 3rd where condition , it started to long running, so i guess the select query at 2nd condition taken long time on execution