0

There is a third party app which generates a high-cost query that has a join on multiple tables.

I created a materialized view on some of the tables using the same join that is originated in the Application query and used rewrite hint. The hint is respected by the optimizer and the materialized view is used. What should I do to make optimizer perform a nested loop join between the materialized view and other tables?

Eg:

SELECT /*+ rewrite */
 tab1.col1, tab1.col2, tab1.col3
 FROM tab1,
 tab2,
 tab3,
 tab4
 WHERE tab1.col1 = tab2.col1
 AND tab2.col2 = tab3.col1
 AND tab4.col1 = tab3.col1
 AND tab4.col1 = :1;

I created a Materialized view as below:

CREATE MATERIALIZED VIEW tst_mv
BUILD IMMEDIATE
ENABLE QUERY REWRITE
AS
 SELECT tab1.col1, tab1.col2, tab1.col3
 FROM tab1, tab2, tab3
 WHERE tab1.col1 = tab2.col1 AND tab2.col2 = tab3.col1;

I tried with the hint as /*+ rewrite use_nl(tst_mv tab4) */ but no luck. Any pointers?

Balazs Papp
41.5k2 gold badges29 silver badges47 bronze badges
asked Feb 1, 2019 at 14:37

1 Answer 1

1

Is that really your query and MV? tab3.col1 is not in it, but joining tab4 requires it because of tab4.col1 = tab3.col1. tab3.col1 = tab2.col2, so tab2.col2 = tab4.col1, but tab2.col2 is also not in the MV.

If I create this:

create table tab1(col1 number, col2 number, col3 number);
create table tab2(col1 number, col2 number);
create table tab3(col1 number);
create table tab4(col1 number);
alter session set query_rewrite_integrity=stale_tolerated;
CREATE MATERIALIZED VIEW tst_mv
BUILD IMMEDIATE
ENABLE QUERY REWRITE
AS
 SELECT tab1.col1, tab1.col2, tab1.col3
 FROM tab1, tab2, tab3
 WHERE tab1.col1 = tab2.col1 AND tab2.col2 = tab3.col1;
explain plan for
SELECT /*+ rewrite */
 tab1.col1, tab1.col2, tab1.col3
 FROM tab1,
 tab2,
 tab3,
 tab4
 WHERE tab1.col1 = tab2.col1
 AND tab2.col2 = tab3.col1
 AND tab4.col1 = tab3.col1
 AND tab4.col1 = :B1;
select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------
Plan hash value: 1776227436
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 91 | 8 (0)| 00:00:01 |
|* 1 | HASH JOIN | | 1 | 91 | 8 (0)| 00:00:01 |
| 2 | MERGE JOIN CARTESIAN| | 1 | 78 | 6 (0)| 00:00:01 |
|* 3 | HASH JOIN | | 1 | 65 | 4 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | TAB1 | 1 | 39 | 2 (0)| 00:00:01 |
|* 5 | TABLE ACCESS FULL | TAB2 | 1 | 26 | 2 (0)| 00:00:01 |
| 6 | BUFFER SORT | | 1 | 13 | 4 (0)| 00:00:01 |
|* 7 | TABLE ACCESS FULL | TAB4 | 1 | 13 | 2 (0)| 00:00:01 |
|* 8 | TABLE ACCESS FULL | TAB3 | 1 | 13 | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
 1 - access("TAB2"."COL2"="TAB3"."COL1" AND
 "TAB4"."COL1"="TAB3"."COL1")
 3 - access("TAB1"."COL1"="TAB2"."COL1")
 5 - filter("TAB2"."COL2"=TO_NUMBER(:B1))
 7 - filter("TAB4"."COL1"=TO_NUMBER(:B1))
 8 - filter("TAB3"."COL1"=TO_NUMBER(:B1))
Note
-----
 - dynamic statistics used: dynamic sampling (level=2)

TST_MV is not used. If I create another MV with tab3.col1 included, then add use_nl, that MV is used with a nested loops join:

CREATE MATERIALIZED VIEW tst_mv2
BUILD IMMEDIATE
ENABLE QUERY REWRITE
AS
 SELECT tab1.col1, tab1.col2, tab1.col3, tab3.col1 as tab3_col1
 FROM tab1, tab2, tab3
 WHERE tab1.col1 = tab2.col1 AND tab2.col2 = tab3.col1;
explain plan for
SELECT /*+ rewrite use_nl(tab4) */
 tab1.col1, tab1.col2, tab1.col3
 FROM tab1,
 tab2,
 tab3,
 tab4
 WHERE tab1.col1 = tab2.col1
 AND tab2.col2 = tab3.col1
 AND tab4.col1 = tab3.col1
 AND tab4.col1 = :B1;
 select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------
Plan hash value: 1384405329
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 65 | 4 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 65 | 4 (0)| 00:00:01 |
|* 2 | MAT_VIEW REWRITE ACCESS FULL| TST_MV2 | 1 | 52 | 2 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | TAB4 | 1 | 13 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
 2 - filter("TST_MV2"."TAB3_COL1"=TO_NUMBER(:B1))
 3 - filter("TAB4"."COL1"=TO_NUMBER(:B1))
Note
-----
 - dynamic statistics used: dynamic sampling (level=2)
answered Feb 1, 2019 at 14:59
1
  • My apologies, the second one you did was correct. In the actual query, apart from MV which is on 2 tables, there are 3 other tables. I will retry again by using the hint to see how optimizer behaves. Commented Feb 1, 2019 at 15:08

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.