Merge join cartesian tips
Oracle Database Tips by Donald BurlesonDecember 12, 2015
The use of a merge join cartesian is very expensive to
Oracle, and are only appropriate in rare cases where one of the tables has a
very small number of rows.
There are several reasons that your SQL will do a Cartesian join. Cartesian
joins can also be caused by:
Missing table join
condition to WHERE clause -
As for the cartesian
merge join, first, carefully check your WHERE clause to ensure that you have
provided the proper join conditions (e.g. where a.primary_key=
bugs (see _optimizer_transitivity_retain)
- Incomplete or stale schema statistics can cause a merge join cartesian.
notes that 10g dynamic sampling removed a merge join cartesian, taking a
query down from 240 sec. to 20 sec. a 12x performance improvement using
sampling to remove the merge join cartesian:
dynamic_sampling(l1 1) dynamic_sampling(l3 1) dynamic_sampling(l2 1)
dynamic_sampling(1 1) dynamic_sampling(a 1) */
a.deptid, l2.tree_node_num, a.ACCOUNT, SUM (a.posted_total_amt)
FROM PS_LEDGER a,
PSTREESELECT05 l . . .
Optimizer Issues with merge join Cartesian
As of 10g and beyond the optimizer will seldom invoke an
inappropriate merge join cartesian (due to bugs with transitive closure where a
join condition is lost to the optimizer. Starting in 10g, the undocumented
parameter _optimizer_transitivity_retain=true which causes issues,
especially when query_rewrite_enabled=true.
Syed Jaffar published an interesting issue with a Oracle9i merge join
cartesian, noting a query that was taking 5 minutes on AIX yet ran for two days
on an equivalent 9i HP/UX platform:
max(cust_code), nvl(abs(sum(run_offs_sar)), 0),
Following is the query and its execution plan on AIX
nvl(abs(sum(inst_amt_sar)), 0), nvl(abs(sum(bal_sar)), 0)
FROM account a
WHERE acct_no = '00100100120'
AND as_of_date = (SELECT max(as_of_date)
FROM account b
WHERE b.acct_no = a.acct_no
AND b.run_offs_sar <> 0)
Execution Plan (AIX)
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=602 Card=1 Bytes=55)
1 0 SORT (AGGREGATE)
2 1 VIEW (Cost=602 Card=1 Bytes=55)
3 2 FILTER
4 3 SORT (GROUP BY) (Cost=602 Card=1 Bytes=75)
5 4 HASH JOIN (Cost=529 Card=167 Bytes=12525)
6 5 PARTITION RANGE (ALL)
7 6 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'A_ACCOUNT' (Cost=264 Card=167
8 7 INDEX (SKIP SCAN) OF 'IDX_DT_ACCT_FLAG' (NON-UNIQUE) (Cost=189 Card=167)
9 5 PARTITION RANGE (ALL)
10 9 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'A_ACCOUNT' (Cost=264 Card=167
11 10 INDEX (SKIP SCAN) OF 'IDX_DT_ACCT_FLAG' (NON-UNIQUE) (Cost=189
Execution Plan (HP)
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=630319908 Card=1 Bytes=55)
1 0 SORT (AGGREGATE)
2 1 VIEW (Cost=630319908 Card=1602 Bytes=88110)
3 2 FILTER
4 3 SORT (GROUP BY) (Cost=630319908 Card=1602 Bytes=107334)
5 4 MERGE JOIN (CARTESIAN) (
7 6 Cost=630319180 Card=225809 Bytes=15129203)
6 5 PARTITION RANGE (ALL)TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'A_ACCOUNT'
(Cost=700 Card=440 Bytes=10560)
8 7 INDEX (SKIP SCAN) OF 'IDX_DT_ACCT_FLAG' (NON-UNIQUE) (Cost=519 Card=513)
9 5 BUFFER (SORT) (Cost=630319208 Card=513 Bytes=22059)
10 9 PARTITION RANGE (ALL)
11 10 TABLE ACCESS (FULL) OF 'A_ACCOUNT' (Cost=1432542 Card=513 Bytes=22059)
I found that the only difference was in the setting of the ?query_rewrite_enabled?
parameter. On AIX this parameter was set to TRUE and on HP it was at the
default setting of FALSE.
After setting this parameter to TRUE on HP, the query achieved the same
response time as on AIX.
There is a (hidden) parameter _optimizer_transitivity_retain which is
set to true in version 10g. This over comes the big problem of transitive
closure behavior when query_rewrite_enabled is not set to true.
Here are my additional notes on merge join cartesian:
Get the Complete
Oracle SQL Tuning Information
The landmark book
SQL Tuning The Definitive Reference" is
filled with valuable information on Oracle SQL Tuning.
This book includes scripts and tools to hypercharge Oracle 11g
performance and you can
for 30% off directly from the publisher.