|
|
Create a materialized view
from an existing table
Article by Rampant author Arup Nanda
|
|
Suppose you have a table and you now want to
convert that to an MV. In other words, you want to re-point that arrow
initially pointed at the table to the materialized view properties:

Can you do it? Yes, of course you can. Since at the segment level it
is the same, Oracle allows you to do it. When you create an MV, you can
use a special clause ON PREBUILT TABLE. Here is how you create a
materialized view in the
regular approach:
create materialized view mv1 never refresh as select cast(count (1)
as number(10)) cnt from t1;
If you check the objects created:
SQL> select object_id, data_object_id, object_type 2 from user_objects
3 where object_name = 'MV1';
OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
---------- -------------- ------------------- 74842 74842 TABLE
74843 MATERIALIZED VIEW
So, it creates two objects – a table and an materialized view - anyway. Note a very
important difference though: the DATA_OBJECT_ID for the materialized view object is null.
If you drop the materialized view and check for the objects:
SQL> drop materialized view mv1;
Materialized View dropped.
SQL> select object_id, data_object_id, object_type 2 from user_objects
3 where object_name = 'MV1';
no rows selected
Even though there were two objects – a table and an MV, when you
dropped the MV, both were dropped. The table object didn’t have an
independent existence. Dropping the materialized view drops the table automatically.
Now, in the modified approach, you first create the table in the same
name as the materialized view you are going to create:
SQL> create table mv1 (cnt number(10));
Next you create the materialized view by adding a new clause called ON PREBUILT TABLE
shown below:
create materialized view mv1
on prebuilt table
never refresh as select cast(count (1) as number(10)) cnt from t1;
Now there will be two objects as well – one table and one MV. The
materialized view simply took over the command over the segment but since the table already
existed, it did not recreate the table object. So there are still only 2
objects.
One concern: since you created the table manually, can you
accidentally drop it? Let’s see:
SQL> drop table mv1; drop table mv1 * ERROR at line 1:
ORA-12083: must use DROP MATERIALIZED VIEW to drop "ARUP"."MV1"
That answers it. The table simply loses its independent existence.
However, see what happens when you drop the MV:
SQL> DROP MATERIALIZED VIEW mv1;
Materialized view dropped.
Now check the segment:
SQL> select segment_type 2 from user_segments 3 where segment_name =
'MV1';
SEGMENT_TYPE ------------------ TABLE
The segment still exists! When you dropped the MV, the segment was not
dropped; it simply reverted to being a table. You can confirm that by
checking the objects view:
OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE ---------- --------------
------------------- 77432 77432 TABLE
Voila! The object still exists as a table. Previously you saw dropping
the materialized view removed all the objects and the segment. However, in this approach
the segment was preserved. Since it reverted to a table, you can do all
things possible in a table – select from it, create index, and - most
important – modify the column. You can alter the column to make
NUMBER(11).
SQL> alter table mv1 modify (cnt number(11));
Table altered.
Now, create the materialized view again:
create materialized view mv1 on prebuilt table never refresh as
select cast(count (1) as number(11)) cnt from t1;
That’s it. The materialized view is altered. The whole process took about a few
seconds, and since you didn’t have to recreate the segment, you saved
enormous load on the database. Here a schematic representation of what
happened.

Now you know how powerful prebuilt table option is. It only affects how
you define the MV; nothing else. All other properties of the materialized
view remain
intact. The end users don’t even know about the prebuilt table option; but
for the DBA it remains a powerful tool in the arsenal. As a best practice
I recommend creating any MV, regardless of size, with the ON PREBUILT
TABLE clause. In small tables you probably don’t see a huge advantage; but
what if today’s small table grows to a large one tomorrow? It’s better to
be safe than sorry.
Conversion to the New Approach
Now that you understand the power of the prebuilt option, you may be
wondering how to convert the existing Materialized Views to the new
clause. Unfortunately there is no conversion path. You have to drop and
recreate the Materialized Views. That is why this time – when we are
moving Materialized Views to new tablespaces – we have the golden
opportunity.
One approach is to create new tables with new names
and then rename them. Here are the steps:
1. Create a table with
nologging clause from the old MV
create table new_mv1 nologging as select * from mv1;
2. Capture the materialized view definition from the data dictionary:
select dbms_metadata.get_ddl ('MATERIALIZED_VIEW','MV1') from dual ;
DBMS_METADATA.GET_DDL('MATERIALIZED_VIEW','MV1')
------------------------------------------------ CREATE MATERIALIZED
VIEW "ARUP"."MV1" ("CNT") ORGANIZATION HEAP PCTFREE 10 … and so on …
3. Spool this to a file to be executed later.
4. Edit this file
to place ON PREBUILT TABLE CLAUSE.
CREATE MATERIALIZED VIEW "ARUP"."MV1" ("CNT") ORGANIZATION HEAP ON
PREBUILT TABLE PCTFREE 10
5. Take a Data Pump export with CONTENTS=METADATA_ONLY option. This
creates all relevant privileges on the export dump file. Keep it aside.
6. Drop the Materialized View MV1.
7. Rename table NEW_MV1 to
MV1
8. Execute the script you created earlier to recreate the MV.
9. Import the export dump file. It will recreate all the privileges.
This is slow; but the best approach since it generates minimum amount
of redo and undo.
|