Pro Oracle Database 11g Administration (62 page)

Read Pro Oracle Database 11g Administration Online

Authors: Darl Kuhn

Tags: #Oracle DBA

BOOK: Pro Oracle Database 11g Administration
7.86Mb size Format: txt, pdf, ePub

Creating a Complete-Refreshable Materialized View

This section explains how to set up an MV that is periodically completely refreshed, which is about the simplest example possible. Complete refreshes are appropriate for MVs that have base tables in which significant portions of the rows change from one refresh interval to the next. Complete refreshes are also required in situations where a fast refresh isn’t possible (due to restrictions imposed by Oracle—more on this later in the chapter).


Note
To create an MV, you need both the CREATE MATERIALIZED VIEW system privilege and the CREATE TABLE

system privilege.

The example in this section uses the following base table named SALES: create table sales(

sales_id number

,sales_amt number

,region_id number

,sales_dtt timestamp

,constraint sales_pk primary key(sales_id)

);

365

CHAPTER 15 ■ MATERIALIZED VIEWS

Insert some sample data into the SALES table:

insert into sales values(1,101,100,sysdate-50);

insert into sales values(2,511,200,sysdate-20);

insert into sales values(3,11,100,sysdate);

commit;

The next step is to create the MV, using a CREATE MATERIALIZED VIEW...AS SELECT statement. This statement names the MV, specifies its attributes, and defines the SQL query on which the MV is based: create materialized view sales_mv

segment creation immediate

refresh

complete

on demand

as

select

sales_amt

,sales_dtt

from sales;

The SEGMENT CREATION IMMEDIATE clause is available with Oracle 11
g
release 2 and higher. It instructs Oracle to create the segment and allocate an extent when you create the MV. This was the behavior in previous versions of Oracle. If you don’t want immediate segment creation, use the SEGMENT CREATION

DEFERRED clause. If the newly created MV has any rows in it, then segments are created and extents are allocated regardless of whether you use SEGMENT CREATION DEFERRED.

Let’s look at the USER_MVIEWS data dictionary to verify that the MV was created as expected. Here’s the query to run:

select

mview_name

,refresh_method

,refresh_mode

,build_mode

,fast_refreshable

from user_mviews

where mview_name = 'SALES_MV';

Here’s the output for this MV:

MVIEW_NAME REFRESH_ REFRESH_MODE BUILD_MOD FAST_REFRESHABLE

------------ -------- ------------ --------- --------------------

SALES_MV COMPLETE DEMAND IMMEDIATE NO

It’s also informative to inspect the USER_OBJECTS and USER_SEGMENTS views to see what has been created. When you query USER_OBJECTS, notice that several objects have been created: select

object_name

,object_type

from user_objects

where object_name like 'SALES%'

order by object_name;

Here’s the corresponding output:

OBJECT_NAME OBJECT_TYPE

-------------------- --------------------

366

CHAPTER 15 ■ MATERIALIZED VIEWS

SALES TABLE

SALES_MV MATERIALIZED VIEW

SALES_MV TABLE

SALES_PK INDEX

The MV is a logical container that stores data in a regular database table. Querying the USER_SEGMENTS view shows the base table, its primary-key index, and the table that stores data returned by the MV query:

select

segment_name

,segment_type

from user_segments

where segment_name like 'SALES%'

order by segment_name;

Here’s the output for this example:

SEGMENT_NAME SEGMENT_TYPE

-------------------- --------------------

SALES TABLE

SALES_PK INDEX

SALES_MV TABLE


Note
Oracle sometimes automatically creates an index on the MV. In this scenario, no index for the MV was created.

Finally, let’s look at how to refresh the SALES_MV MV. Here’s the data contained in SALES_MV: SQL> select sales_amt, to_char(sales_dtt,'dd-mon-yyyy') from sales_mv; Here’s the output:

SALES_AMT TO_CHAR(SALES_DTT

---------- -----------------

101 17-jun-2010

511 17-jul-2010

11 06-aug-2010

Next, insert some additional data into the base SALES table:

SQL> insert into sales values(4,99,200,sysdate);

SQL> insert into sales values(5,127,300,sysdate);

Now you attempt to initiate a fast refresh of the MV using the REFRESH procedure of the DBMS_MVIEW

package. This example passes two parameters to the REFRESH procedure: the name and the refresh method. The name is SALES_MV, and the parameter is F (for
fast
): SQL> exec dbms_mview.refresh('SALES_MV','F');

Because this MV wasn’t created in conjunction with an MV log, a fast refresh isn’t possible. The following error is thrown:

ORA-12004: REFRESH FAST cannot be used for materialized view "MV"."SALES_MV"

367

CHAPTER 15 ■ MATERIALIZED VIEWS

5. Users can query data from the MV, which contains a point-in-time snapshot of the base table’s data.

In the next section, a more complicated example shows you how to set up a fast-refreshable MV.

Creating a Fast-Refreshable Materialized View

When you create a fast-refreshable MV, it initially populates the MV table with the entire result set of the MV query. After the initial result set is in place, only data modified (in the base table) since the last refresh needs to be applied to the MV. In other words, any updates, inserts, or deletes from the master table that have occurred since the last refresh are copied over. This feature is appropriate when you have a small amount of changes to a base table over a period of time compared to the total number of rows in the table.

Here are the steps to implement a fast-refreshable MV:

1. Create a base table (if it’s not already created).

2. Create an MV log on the base table.

3. Create an MV as fast-refreshable.

This example first creates a base table. In most environments, you already have a base table in place. For illustrative purposes, here’s the table-creation script and some sample data: create table sales(

sales_id number

,sales_amt number

,region_id number

,sales_dtt timestamp

,constraint sales_pk primary key(sales_id)

);

--

insert into sales values(1,101,100,sysdate-50);

insert into sales values(2,511,200,sysdate-20);

insert into sales values(3,11,100,sysdate);

commit;

A fast-refreshable MV requires an MV log on the base table. When a fast refresh occurs, the MV log must have a unique way to identify which records have been modified and thus need to be refreshed.

You can do this two different approaches. One method is to specify the PRIMARY KEY clause when you create the MV log, and the other is to specify the ROWID clause. If the underlying base table has a primary key, then use the primary key–based MV log. If the underlying base table has no primary key, then you have to create the MV log using ROWID. In most cases, you’ll probably have a primary key defined for every base table. However, the reality is that some systems are poorly designed or have some rare reason for a table not to have a primary key.

In this example, a primary key is defined on the base table, so you create the MV log with the PRIMARY KEY clause:

SQL> create materialized view log on sales with primary key;

If there was no primary key defined on the base table, this error is thrown when attempting to create the MV log:

ORA-12014: table does not contain a primary key constraint

369

CHAPTER 15 ■ MATERIALIZED VIEWS

If the base table has no primary key, and you don’t have the option to add one, you must specify ROWID when you create the MV log:

SQL> create materialized view log on sales with rowid;

Now that you’ve created the MV log, you can create the fast-refreshable MV. There are a couple of interesting architectural considerations to point out. If there is no MV log on the base table, then Oracle doesn’t allow you to create a fast-refreshable MV. This error is thrown: ORA-23413: table does not have a materialized view log.

Also, when you create the fast-refreshable MV, you must specify whether it’s refreshed via the PRIMARY KEY (which is the default) or via the ROWID. This example uses a table with a primary key and an MV log created with a primary key. In this example, the MV is fast-refreshed via a primary key. When you use a primary key–based fast-refreshable MV, the primary-key column(s) of the base table must be part of the fast-refreshable MV SELECT statement:

create materialized view sales_mv

segment creation immediate

refresh

with primary key

fast

on demand

as

select

sales_id

,sales_amt

,sales_dtt

from sales;

At this point, it’s useful to inspect the objects that are associated with the MV. The following query selects from USER_OBJECTS:

select

object_name

,object_type

from user_objects

where object_name like '%SALES%'

order by object_name;

Here are the objects that have been created:

OBJECT_NAME OBJECT_TYPE

-------------------- --------------------

MLOG$_SALES TABLE

RUPD$_SALES TABLE

SALES TABLE

SALES_MV MATERIALIZED VIEW

SALES_MV TABLE

SALES_PK INDEX

SALES_PK1 INDEX

370

CHAPTER 15 ■ MATERIALIZED VIEWS

Several objects in the previous output require some explanation:

• MLOG$_SALES

• RUPD$_SALES

• SALES_PK1

First, when an MV log is created, a corresponding table is also created that stores the rows in the base table that changed and how they changed (insert, update, or delete). The MV log table name is of the format MLOG$_.

A table is also created with the format RUPD$_. Oracle automatically creates this RUPD$ table when you create a fast-refreshable MV using a primary key. It’s there to support the updateable MV feature. You don’t have to worry about this table unless you’re dealing with updatable MVs (see the
Oracle Advanced Replication Guide
for more details on updatable MVs). If you’re not using the updatable MV feature, then you can ignore the RUPD$ table.

Oracle also creates an index with the format _PK1. This index is automatically created for primary key–based MVs and is based on the primary-key column(s) of the base table. If this is a ROWID instead of a primary key, then the index name has the format I_SNAP$_ and is based on the ROWID. If you don’t explicitly name the primary-key index on the base table, then Oracle gives the MV table primary-key index a system-generated name such as SYS_C008780.

Now that you understand the underlying architectural components, let’s look at the data in the MV: SQL> select sales_amt, to_char(sales_dtt,'dd-mon-yyyy') from sales_mv; Here’s the output:

SALES_AMT TO_CHAR(SALES_DTT

---------- -----------------

101 12-jun-2010

511 12-jul-2010

11 01-aug-2010

Let’s add two records to the base SALES table:

insert into sales values(4,99,200,sysdate);

insert into sales values(5,127,300,sysdate);

commit;

At this point, it’s instructional to inspect the M$LOG table. You should see two records that identify how the data in the SALES table has changed:

SQL> select count(*) from mlog$_sales;

There are two records:

COUNT(*)

----------

2

Next, let’s refresh the MV. This MV is fast-refreshable, so you call the REFRESH procedure of the DBMS_MVIEW package with the F (for
fast
) parameter:

SQL> exec dbms_mview.refresh('SALES_MV','F');

A quick inspection of the MV shows two new records:

SQL> select sales_amt, to_char(sales_dtt,'dd-mon-yyyy') from sales_mv; Here’s some sample output:

371

CHAPTER 15 ■ MATERIALIZED VIEWS

SALES_AMT TO_CHAR(SALES_DTT

---------- -----------------

101 12-jun-2010

511 12-jul-2010

11 01-aug-2010

99 01-aug-2010

127 01-aug-2010

In addition, the count of the MLOG$ has dropped to zero. After the MV refresh is complete, those records are no longer required:

SQL> select count(*) from mlog$_sales;

Here’s the output:

COUNT(*)

----------

0

You can verify the last method in which an MV was refreshed by querying the USER_MVIEWS view: select

mview_name

,last_refresh_type

,last_refresh_date

from user_mviews

order by 1,3;

Here’s some sample output:

Other books

The Death of an Irish Tinker by Bartholomew Gill
Panda-Monium by Bindi Irwin
After the Crash by Michel Bussi
Hoy caviar, mañana sardinas by Carmen Posadas y Gervasio Posadas
The Gunsmith 385 by J. R. Roberts
Berlina's Quest by James Hartley
Nail - A Short Story by Kell Inkston
Buckskin Bandit by Dandi Daley Mackall