view optimization (10gr2)

When talking about view optimization, we need to know about mergeable view and unmergeable view. 10gr2 concept gives very clear definition.

 

The optimizer can merge a view into a referencing query block when the view has one or more base tables, provided the view does not contain:

  • set operators (UNION, UNION ALL, INTERSECT, MINUS)
  • a CONNECT BY clause
  • a ROWNUM pseudocolumn
  • aggregate functions (AVG, COUNT, MAX, MIN, SUM) in the select list

When a view contains one of the following structures, it can be merged into a referencing query block only ifcomplex view mergingis enabled (as described below):

  • a GROUP BY clause
  • a DISTINCT operator in the select list

View merging is not possible for a view that has multiple base tables if it is on the right side of an outer join. If a view on the right side of an outer join has only one base table, however, the optimizer can use complex view merging even if an expression in the view can return a non-null value for a NULL. See"Views in Outer Joins"for more information.

 

We can use three hint to instruct CBO to chose a better execution plan when there is view in query.

merge

This is easy to understand, if a view is not merged in a query and you think it may faster after merge, you can use this hint.

un_merge

Consider this situation, you have several well-optimized views. Accessing any of them will be very smoothly. But when you put these views in to a query, oracle merge these view which returns a very slow execution plan. How can you to resolve this situation? you can use un_merge.Since the orignal view is optimized very well then why we merge them? Just use them. Lets see below example

SQL> select count(*) from DBA_OBJECTS;

  COUNT(*)
----------
     56714

Elapsed: 00:00:00.22
SQL> select count(*) from DBA_SEQUENCES;

  COUNT(*)
----------
       363

Elapsed: 00:00:00.04

 

 

We can see accessing these two data dictionary view is very fast.

SQL> SELECT COUNT(*)  FROM DBA_SEQUENCES A, DBA_OBJECTS B;

  COUNT(*)
----------
  20587182

Elapsed: 00:00:23.68

 

But the query for puting them together run very slow. Why ? If you check execution plan, you will find the orignal well optiomized view is merged. Now lets use the un_merge

SQL> SELECT /*+ NO_MERGE(A) NO_MERGE(B) */ COUNT(*)  FROM DBA_SEQUENCES A, DBA_OBJECTS B;

  COUNT(*)
----------
  20587182

Elapsed: 00:00:04.16

Check the execution plan , we see view not merged.

SQL> explain plan for SELECT /*+ NO_MERGE(A) NO_MERGE(B) */ COUNT(*)  FROM DBA_SEQUENCES A, DBA_OBJECTS B;

Explained.

Elapsed: 00:00:00.04
SQL> select * from table(dbms_xplan.display());

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2492168462

---------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |               |     1 |       | 66454  (10)| 00:13:18 |
|   1 |  SORT AGGREGATE                   |               |     1 |       |            |          |
|   2 |   MERGE JOIN CARTESIAN            |               |    19M|       | 66454  (10)| 00:13:18 |
|   3 |    VIEW                           | DBA_SEQUENCES |   363 |       |   173   (6)| 00:00:03 |
|*  4 |     HASH JOIN                     |               |   363 |  5808 |   173   (6)| 00:00:03 |
|   5 |      TABLE ACCESS FULL            | USER$         |    87 |   261 |     3   (0)| 00:00:01 |
|*  6 |      HASH JOIN                    |               |   363 |  4719 |   169   (5)| 00:00:03 |
|   7 |       INDEX FULL SCAN             | I_SEQ1        |   363 |  1815 |     1   (0)| 00:00:01 |
|   8 |       TABLE ACCESS FULL           | OBJ$          | 57907 |   452K|   166   (4)| 00:00:02 |
|   9 |    BUFFER SORT                    |               | 52840 |       | 66454  (10)| 00:13:18 |
|  10 |     VIEW                          | DBA_OBJECTS   | 52840 |       |   183  (10)| 00:00:03 |
|  11 |      UNION-ALL                    |               |       |       |            |          |
|* 12 |       FILTER                      |               |       |       |            |          |
|* 13 |        HASH JOIN                  |               | 57903 |  4636K|   180  (10)| 00:00:03 |
|  14 |         TABLE ACCESS FULL         | USER$         |    87 |   261 |     3   (0)| 00:00:01 |
|* 15 |         TABLE ACCESS FULL         | OBJ$          | 57903 |  4467K|   174   (9)| 00:00:03 |
|* 16 |        TABLE ACCESS BY INDEX ROWID| IND$          |     1 |     8 |     2   (0)| 00:00:01 |
|* 17 |         INDEX UNIQUE SCAN         | I_IND1        |     1 |       |     1   (0)| 00:00:01 |
|  18 |       NESTED LOOPS                |               |     2 |    12 |     3   (0)| 00:00:01 |
|  19 |        INDEX FULL SCAN            | I_LINK1       |     2 |     6 |     1   (0)| 00:00:01 |
|  20 |        TABLE ACCESS CLUSTER       | USER$         |     1 |     3 |     1   (0)| 00:00:01 |
|* 21 |         INDEX UNIQUE SCAN         | I_USER#       |     1 |       |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("U"."USER#"="O"."OWNER#")
   6 - access("O"."OBJ#"="S"."OBJ#")
  12 - filter("O"."TYPE#"<>1 AND "O"."TYPE#"<>10 OR "O"."TYPE#"=1 AND  (SELECT 1 FROM
              "SYS"."IND$" "I" WHERE "I"."OBJ#"=:B1 AND ("I"."TYPE#"=1 OR "I"."TYPE#"=2 OR "I"."TYPE#"=3
              OR "I"."TYPE#"=4 OR "I"."TYPE#"=6 OR "I"."TYPE#"=7 OR "I"."TYPE#"=9))=1)
  13 - access("O"."OWNER#"="U"."USER#")
  15 - filter("O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND
              "O"."LINKNAME" IS NULL)
  16 - filter("I"."TYPE#"=1 OR "I"."TYPE#"=2 OR "I"."TYPE#"=3 OR "I"."TYPE#"=4 OR
              "I"."TYPE#"=6 OR "I"."TYPE#"=7 OR "I"."TYPE#"=9)
  17 - access("I"."OBJ#"=:B1)
  21 - access("L"."OWNER#"="U"."USER#")

44 rows selected.

Elapsed: 00:00:00.04

 

push_pred

In predicate pushing, the optimizer "pushes" the relevant predicates from the containing query block into the view query block. For views that are not merged, this technique improves the subplan of the unmerged view because the database can use the pushed-in predicates to access indexes or to use as filters.

For example, suppose you create a view that references two employee tables. The view is defined with a compound query that uses the UNION set operator, as follows:

CREATE VIEW all_employees_vw AS
  ( SELECT employee_id, last_name, job_id, commission_pct, department_id
    FROM   employees )
  UNION
  ( SELECT employee_id, last_name, job_id, commission_pct, department_id
    FROM   contract_workers );

You then query the view as follows:

SELECT last_name
FROM   all_employees_vw
WHERE  department_id = 50;

Because the view is a compound query, the optimizer cannot merge the view's query into the accessing query block. Instead, the optimizer can transform the accessing statement by pushing its predicate, the WHERE clause condition department_id=50, into the view's compound query. The equivalent transformed query is as follows:

SELECT last_name
FROM   ( SELECT employee_id, last_name, job_id, commission_pct, department_id
         FROM   employees
         WHERE  department_id=50
         UNION
         SELECT employee_id, last_name, job_id, commission_pct, department_id
         FROM   contract_workers
         WHERE  department_id=50 );

 

posted on 2013-04-24 15:29  kramer  阅读(240)  评论(0编辑  收藏  举报

导航