Materialized Views

advertisement
CHAPTER 15
Materialized Views
Materialized Views (MVs)
• Sometimes people new to MVs are confused by the term
“materialized view”.
• An MV is basically a table that is periodically refreshed
with data from a SQL query.
• Oracle provides numerous configurations and
management features for MVs.
• Fairly robust and flexible feature that has been available
since version 7.
Primary Uses for MVs
• Replicating of data to offload query workloads to separate
reporting databases.
• Improving performance of queries by periodically
computing and storing the results of complex
aggregations of data, which lets users query point-in-time
results (of the complex queries).
Basic Materialized View Create Statement
• This is a complete refresh, on demand MV based on query that
selects from the SALES table:
create materialized view sales_mv
segment creation immediate
refresh
complete
on demand
as
select
sales_amt
,sales_dtt
from sales;
Using the Complete Refresh Mechanism
• Data is deleted from the underlying table.
• MV is completely refreshed with data from the base table.
SQL> exec dbms_mview.refresh('SALES_MV','C');
Complete Refresh Architectural Steps
1. Users/applications create transactions.
2. Data is committed in the base table.
3. A complete refresh is manually initiated with the
DBMS_MVIEW package.
4. Data in the underlying MV is deleted and completely
refreshed with the contents of the base table.
5. Users can query data from the MV, which contains a
point-in-time snapshot of the base table’s data.
Complete Refresh Architectural
Components
Creating a Fast Refreshable MV
1.
2.
3.
Create a base table (if it’s not already created).
Create an MV log on the base table.
Create an MV as fast-refreshable.
SQL> create materialized view log on sales with primary key;
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;
Using the Fast Refresh Mechanism
• MV log is a table that stores incremental changes to the
data in the base table.
• MV log is created on the base table.
• Since the base table has an MV log, the MV can be fast
refreshed, meaning that only the data changes since the
last time the MV was refreshed need to be applied.
SQL> exec dbms_mview.refresh('SALES_MV','F');
Fast Refresh Architecture Steps
1. Users create transactions.
2. Data is committed in the base table.
3. An internal trigger on the base table populates the MV
log table.
4. A fast refresh is initiated via the DBMS_MVIEW
package.
5. DML changes that have been created since the last
refresh are applied to the MV. Rows no longer needed
by the MV are deleted from the MV log.
6. Users can query data from the MV, which contains a
point-in-time snapshot of the base table’s data.
Fast Refresh Architectural Components
MV and MV Log are instantiated as tables
• Most database features that apply to tables can be
applied to MVs and MV logs:
• Storage and tablespace placement
• Indexing
• Partitioning
• Compression
• Encryption
• Logging
• Parallelism
Specifying Storage Attributes for an MV
create materialized view inv_mv
pctused 95
pctfree 5
tablespace mv_data
using index tablespace mv_index
as
select
inv_id
,inv_desc
from inv;
Creating Indexes on MVs
• MV stores data in a database table.
• You can create indexes on this MV to improve
performance.
• For example, if there is a column in an MV that is heavily
referenced in WHERE clauses of SQL statements, then
consider creating an index on this column (especially if it
is highly selectable):
SQL> create index inv_mv_idx1 on inv_mv(region_id)
tablespace mv_index;
Partitioning Materialized Views
• You can partition an MV table like any other regular table in the database.
• If you work with large MVs, you may want to consider partitioning to
better manage and maintain a large table.
• Use the PARTITION clause when you create the MV.
• This example builds an MV that is partitioned by range on the DATE_ID
column:
create materialized view inv_mv
partition by range (date_id)
(partition p1 values less than (20100101)
,partition p2 values less than (20110101)
,partition p3 values less than (20120101))
refresh on demand complete with rowid
as
select
inv_id, inv_desc,date_id
from inv;
Compressing a Materialized View
• When you create an MV, an underlying table is created to
store the data.
• Because this table is a regular database table, you can
implement features such as compression. For example:
create materialized view inv_mv
compress
as
select
inv_id
,inv_desc
from inv;
Encrypting Materialized View Columns
• When you create an MV, an underlying table is created to store
the data.
• Because this table is a regular database table, you can
implement features such as encryption of columns. For
example:
create materialized view inv_mv
(inv_id encrypt no salt
,inv_desc encrypt)
as
select
inv_id inv_id
,inv_desc inv_desc
from inv;
Building a Materialized View on a Prebuilt
Table
• In data-warehouse environments, sometimes you need to
create a table, populate it with large quantities of data,
and then transform it into an MV. Listed next are the steps
for building an MV on a prebuilt table:
1. Create a table.
2. Populate it with data.
3. Create an MV on the table created in step 1.
Creating an Unpopulated Materialized
View
• When you create an MV, you have the option of instructing Oracle
whether or not to initially populate the MV with data.
• For example, if it takes several hours to initially build an MV, you may
want to first define the MV and then populate it as a separate job.
• Use the BUILD DEFERRED clause to instruct Oracle not to initially
populate the MV with the results of the query:
create materialized view inv_mv
tablespace mv_data
build deferred
refresh complete on demand
as
select
inv_id
,inv_desc
from inv;
Creating a Materialized View Refreshed
on Commit
• Use ON COMMIT when you need the data from the
master table immediately reflected in the MV.
• Consider the overhead and availability issues before
implementing this type of MV.
create materialized view inv_mv
refresh
on commit
as
select inv_id, inv_desc from inv;
Creating a Never-Refreshable
Materialized View
• You may never want an MV to be refreshed. For example, you
may want to guarantee that you have a snapshot of table at a
point in time for auditing purposes.
• Specify the NEVER REFRESH clause when you create the MV
to achieve this:
•
create materialized view inv_mv
tablespace mv_data
using index tablespace mv_index
never refresh
as
select
inv_id
,inv_desc
from inv;
Creating Materialized Views for QueryRewrite
• Query rewrite allows the optimizer to recognize that an MV can be
used to fulfill the requirements of a query instead of using the
underlying master (base) tables.
• When users frequently write their own queries and are unaware of the
available MVs, this feature can help greatly with performance.
create materialized view sales_mv
tablespace mv_data
using index tablespace mv_index
enable query rewrite
as
select
sum(sales_amt), b.reg_desc
from sales a, region b
where a.region_id = b.region_id
group by b.reg_desc;
Creating a Fast-Refreshable MV Based
on a Complex Query
• In many situations, when you base an MV on a query that
joins multiple tables, it’s deemed complex, and therefore
is available only for a complete refresh.
• However, in some scenarios, you can create a fastrefreshable MV when you reference two tables that are
joined together in the MV query.
• Use the EXPLAIN_MVIEW procedure of the
DBMS_MVIEW to determine whether it’s possible to fastrefresh a complex query.
Viewing Materialized View DDL
• To quickly view the SQL query on which an MV is based, select
from the QUERY column of DBA/ALL/USER_MVIEWS.
• If you’re using SQL*Plus, first set the LONG variable to a value
large enough to display the entire contents of a LONG column:
SQL> set long 5000
SQL> select query from dba_mviews where
mview_name=UPPER('&&mview_name');
• To view the entire Data Definition Language ()DDL required to
re-create an MV, use the DBMS_METADATA package:
SQL> select
dbms_metadata.get_ddl('MATERIALIZED_VIEW','INV_MV') from
dual;
Dropping a Materialized View
• You may occasionally need to drop an MV. Perhaps a
view is no longer being used, or you need to drop and recreate an MV to change the underlying query on which
the MV is based (such as adding a column to it).
• Use the DROP MATERIALIZED VIEW command to drop
an MV.
SQL> drop materialized view orders_mv;
Re-creating a Materialized View to Reflect
Base-Table Modifications
• There is no ALTER MATERIALIZED VIEW
ADD/DROP/MODIFY <column> statement, you must do
the following to add/delete columns in an MV:
1. Alter the base table.
2. Drop and re-create the MV to reflect the changes in the
base table.
Altering a Materialized View but
Preserving the Underlying Table
• When you drop an MV, you have the option of preserving
the underlying table and its data.
• You may find this approach advantageous when you’re
working with large MVs in data-warehouse environments.
Here are the steps:
1. Alter the base table.
2. Drop the MV, but preserve the underlying table.
3. Modify the underlying table.
4. Re-create the MV using the ON PREBUILT TABLE
clause.
Altering a Materialized View Created on a
Prebuilt Table
• If you originally created an MV using the ON PREBUILT
TABLE clause, then here are the steps for modifying an
MV that was created using the ON PREBUILT TABLE
clause:
1. Alter the base table.
2. Drop the MV. For MVs built on prebuilt tables, this
doesn’t drop the underlying table.
3. Alter the prebuilt table.
4. Re-create the MV on the prebuilt table.
Toggling Redo Logging on a Materialized
View
• In some scenarios you can easily recreate an MV, and know
that you don’t ever need to recover any of its data (because
you can always re-create from the master table).
• By default, redo logging is enabled when you create an MV.
You have the option of specifying that redo not be logged when
an MV is refreshed:
create materialized view inv_mv
nologging
tablespace mv_data
using index tablespace mv_index
as
select
inv_id
,inv_desc
from inv;
Altering Parallelism
• Sometimes an MV is created with a high degree of
parallelism to improve the performance of the creation
process.
SQL> alter materialized view inv_mv parallel 3;
Managing Materialized View Logs
• MV logs are required for fast-refreshable MVs.
• The MV log is a table that stores DML information for a
•
•
•
•
master (base) table.
It’s created in the same database as the master table with
the same user that owns the master table.
You need the CREATE TABLE privilege to create an MV
log.
The MV log is populated by an Oracle internal trigger (that
you have no control over).
This internal trigger inserts a row into the MV log after an
INSERT, UPDATE, or DELETE on the master table.
Creating a Materialized View Log
• Fast-refreshable views require an MV log to be created on
the master (base) table.
• Use the CREATE MATERIALIZED VIEW LOG command
to create an MV log.
• This example creates an MV log on the USERS table,
specifying that the primary key should be used to identify
rows in the MV log:
SQL> create materialized view log on users with primary
key;
Indexing Materialized View Log Columns
• Sometimes you may need better performance from your
fast-refreshing MVs.
• One way to do this is through indexes on columns of the
MV log table. In particular, consider indexing the primarykey column and the SNAPTIME$$ column.
• Oracle potentially uses two columns in WHERE clauses
when refreshing an MV or purging the MV log. Here are
examples of creating indexes on MV log columns:
SQL> create index mlog$_inv_idx1 on
mlog$_inv(snaptime$$) tablespace mv_index;
SQL> create index mlog$_inv_idx2 on mlog$_inv(inv_id)
tablespace mv_index;
Viewing Space Used by a Materialized
View Log
• You should consider periodically checking the space consumed
by an MV log.
• If the space consumed is growing (and never shrinking), you
may have an issue with an MV not successfully refreshing (and
hence causing the MV log never to be purged).
• Here’s a query to check the space of MV logs:
select
segment_name
,tablespace_name
,bytes/1024/1024 meg_bytes
,extents
from dba_segments
where segment_name like 'MLOG$%'
order by meg_bytes;
Shrinking the Space in a Materialized
View Log
• You may encounter the scenario where the MV log wasn’t
purged for some reason.
• After resolving the issue you notice that the MV log has
grown to a large size, and you want to shrink so as to free
up the space it’s unnecessarily consuming:
SQL> alter table mlog$_registrations enable row
movement;
SQL> alter materialized view log on registrations shrink
space;
Checking the Row Count of a Materialized
View Log
• One way of detecting whether an MV log isn’t being purged is
to periodically check the row counts of the MV log tables.
• The following query uses SQL to generate SQL that creates a
script that checks row counts for MV log tables owned by the
currently connected user:
set head off pages 0 lines 132 trimspool on
spo mvcount_dyn.sql
select 'select count(*) || ' || '''' || ': ' || table_name || ''''
|| ' from ' || table_name || ';'
from user_tables
where table_name like 'MLOG%';
spo off;
Moving a Materialized View Log
• If any MV log tables need to be relocated, use the ALTER
MATERIALIZED VIEW LOG ON <table_name> MOVE
statement.
• Specify the name of the master table (and not the
underlying MLOG$ table) on which the MV is created:
SQL> alter materialized view log on inv move tablespace
tbsp2;
Dropping a Materialized View Log
• Use the DROP MATERIALIZED VIEW LOG ON statement
to drop an MV log.
• You don’t need to know the name of the MV log, but you
do need to know the name of the master table on which
the log was created.
SQL> drop materialized view log on inv;
Refreshing Materialized Views
• Sooner or later, you’ll need to refresh an MV manually.
• Usually this is because you’re testing a refresh or
troubleshooting an issue.
• To do so, use SQL*Plus to call the REFRESH procedure
of the DBMS_MVIEW package.
• The procedure takes two parameters: the MV name and
the refresh method.
• This example uses the EXEC[UTE] statement to call the
procedure. The MV being refreshed is INV_MV, and the
refresh method is F (for fast):
SQL> exec dbms_mview.refresh('INV_MV','F');
Automating Refreshes Using a Shell
Script and Scheduling Utility
• Many MVs must be refreshed on a daily basis.
• To achieve this, you can use a Linux/Unix utility such as
cron that calls a shell script to refresh the MVs.
• This approach
• Is easy to implement and maintain
• Makes it easy to create a daily log file for auditing
• Sends e-mail when the job has problems or when the database
isn’t available
Creating an MV with a Refresh Interval
• When you initially create an MV, you have the option of specifying
START WITH and NEXT clauses that instruct Oracle to set up an
internal database job (via the DBMS_JOB package) to initiate the
refresh of an MV on a periodic basis.
• If you omit START WITH and NEXT, then no job is set up, and you
have to use another technique (such as a scheduling utility like cron).
• Example:
create materialized view inv_mv
refresh
start with sysdate+1/1440
next sysdate+1
as
select inv_id, inv_desc
from inv;
Efficiently Performing a Complete Refresh
• Instruct Oracle to truncate the MV instead of use delete.
• This may be desirable for large MV refreshes where it’s
okay for the data not to be available after the truncate and
before the MV is completely refreshed.
• You have the option of instructing Oracle to perform the
removal of data as efficiently as possible via the
ATOMIC_REFRESH parameter.
• When this parameter is set to FALSE, it allows Oracle to
use a TRUNCATE statement instead of a DELETE when
performing a complete refresh:
SQL> exec
dbms_mview.refresh('INV_MV',method=>'C',atomic_refres
h=>false);
Handling the ORA-12034 Error
• The ORA-12034 error is thrown when Oracle determines
that the MV log was created after the last refresh took
place in the associated MV.
• In these scenarios try to perform a complete refresh of the
MV.
• There are several possible causes for this situation:
• The MV log was dropped and re-created.
• The MV log was purged.
• The master table was reorganized.
• The master table was truncated.
• The previous refresh failed.
Viewing Materialized Views’ Last Refresh
Times
• If you work MVs, then you need to become familiar with
various views used for troubleshooting.
• Viewing the last refresh time is oftentimes where you start
the troubleshooting process:
select
mview_name
,to_char(last_refresh_date,'dd-mon-yy hh24:mi:ss')
,refresh_mode
,refresh_method
from user_mviews
order by 2;
Determining Whether a Refresh Is in
Progress
• When troubleshooting, here’s a handy query which shows
which MVs are currently refreshing:
select
sid
,serial#
,currmvowner
,currmvname
from v$mvrefresh;
Monitoring Real-Time Refresh Progress
• The following query is extremely useful for troubleshooting MV refresh issues.
• It shows where the MV is in the refresh process:
select
currmvowner_knstmvr || '.' || currmvname_knstmvr "MVIEW BEING
REFRESHED",
decode(reftype_knstmvr, 1, 'FAST', 2, 'COMPLETE', 'UNKNOWN') reftype,
decode(groupstate_knstmvr, 1, 'SETUP', 2, 'INSTANTIATE',
3, 'WRAPUP', 'UNKNOWN' ) STATE,
total_inserts_knstmvr inserts,
total_updates_knstmvr updates,
total_deletes_knstmvr deletes
from x$knstmvr x
where type_knst = 6
and exists (select 1
from v$session s
where s.sid=x.sid_knst
Understanding Remote-Refresh
Architectures
• There are numerous ways to snap together various MVs
to replicate data. Here is an example:
Determining How Many MVs Reference a
Central MV Log
• If an MV was dropped and unable to un-register itself from a
master MV log table, then records grow indefinitely in the
master MV log table.
• To resolve this issue, you need information regarding which
MVs are tied to which MV logs.
• This query displays the master-table owner information and the
SNAPID (MV ID) of all dependent MVs:
select
mowner
,master base_table
,snapid
,snaptime
from sys.slog$;
Creating a Materialized View Group
• Sometimes for read consistency you’ll want to refresh a group of MVs.
• You use the MAKE procedure of the DBMS_REFRESH package to
create an MV group.
• When you create an MV group, you must specify a name, a commaseparated list of MVs in the group, the next date to refresh, and the
interval used to calculate the next refresh time.
• Here’s an example of a group that consists of two MVs:
begin
dbms_refresh.make(
name
=> 'INV_GROUP'
,list
=> 'INV_MV, REGION_MV'
,next_date => sysdate-100
,interval => 'sysdate+1'
);
end;
/
Determining Materialized Views in a
Group
• When troubleshooting MV groups, it’s useful to start by
displaying what the groups are and what MVs are in each
group:
select
a.owner
,a.name mv_group
,b.name mv_name
from dba_rgroup a
,dba_rchild b
where a.refgroup = b.refgroup
and a.owner = b.owner
order by a.owner, a.name, b.name;
Summary
• MVs are a very powerful feature that allows you to
aggregate information for improving performance and also
for replicating data between database environments.
• MVs are a feature rich utility and as a DBA and developer
you should be aware of this tool and how to implement
and manage these objects.
Download