I just created tables DEPT and EMP like follow :
create table DEPT
( dept_no number , dept_name varchar(32) , dept_desc varchar(32),
CONSTRAINT dept_pk Primary Key (dept_no) );
create table EMP
( emp_no number, dept_no number, CONSTRAINT emp_pk Primary Key (emp_no,dept_no));
insert into dept values (10,'it','desc1');
insert into dept values (20,'hr','desc2');
insert into emp values (1,10);
insert into emp values (2,20);
I created materialized view logs on these tables with rowid and materialized views as follows:
create materialized view log on emp with rowid;
create materialized view log on dept with rowid;
create materialized view empdept_mv refresh fast on commit as
select a.rowid dept_rowid, b.rowid emp_rowid, a.dept_no,b.emp_no
from dept a, emp b
where a.dept_no=b.dept_no ;
select * from emp;
EMP_NO DEPT_NO
---------- ----------
1 10
2 20
3 30
select * from dept;
DEPT_NO DEPT_NAME DEPT_DESC
---------- -------------------------------- --------------------------------
10 it desc1
20 hr desc2
30 it desc3
select * from empdept_mv;
DEPT_ROWID EMP_ROWID DEPT_NO EMP_NO
------------------ ------------------ ---------- ----------
AAAli5AABAAAPZ6AAA AAAli7AABAAAQs6AAA 10 1
AAAli5AABAAAPZ6AAB AAAli7AABAAAQs6AAB 20 2
I inserted a new record and did COMMIT; ..but still when i check the materialized view, the new record is not shown in the materialized view.
insert into dept values (30,'it','desc3');
commit;
insert into emp values (3,30);
commit;
select * from empdept_mv;
DEPT_ROWID EMP_ROWID DEPT_NO EMP_NO
------------------ ------------------ ---------- ----------
AAAli5AABAAAPZ6AAA AAAli7AABAAAQs6AAA 10 1
AAAli5AABAAAPZ6AAB AAAli7AABAAAQs6AAB 20 2
Now, when I run the procedure for Fast and complete refresh as per, The Fast refresh does not update the Mview but the complete refresh does. ( Note: But the Mview is still REFRESH ON COMMIT)
execute DBMS_MVIEW.REFRESH('empdept_mv', 'F', '', TRUE, FALSE, 0,0,0,FALSE, FALSE);
PL/SQL procedure successfully completed.
DEPT_ROWID EMP_ROWID DEPT_NO EMP_NO
------------------ ------------------ ---------- ----------
AAAli5AABAAAPZ6AAA AAAli7AABAAAQs6AAA 10 1
AAAli5AABAAAPZ6AAB AAAli7AABAAAQs6AAB 20 2
execute DBMS_MVIEW.REFRESH('test_mview2', 'C', '', TRUE, FALSE, 0,0,0,FALSE, FALSE);
PL/SQL procedure successfully completed.
DEPT_ROWID EMP_ROWID DEPT_NO EMP_NO
------------------ ------------------ ---------- ----------
AAAli5AABAAAPZ6AAA AAAli7AABAAAQs6AAA 10 1
AAAli5AABAAAPZ6AAB AAAli7AABAAAQs6AAB 20 2
AAAli5AABAAAPZ6AAC AAAli7AABAAAQs6AAC 30 3
The DBMS_MVIEW.EXPLAIN_MVIEW output is as shown : (capability_name --Possible-- msgtxt)
PCT --N--
REFRESH_COMPLETE --Y--
REFRESH_FAST --Y--
REWRITE --N--
PCT_TABLE --N-- Oracle error: see RELATED_NUM and RELATED_TEXT for
details
REFRESH_FAST_AFTER_INSERT --Y--
REFRESH_FAST_AFTER_ONETAB_DML --Y--
REFRESH_FAST_AFTER_ANY_DML --Y--
REFRESH_FAST_PCT --N-- PCT is not possible on any of the detail
tables in the mater
REWRITE_FULL_TEXT_MATCH --N-- Oracle error: see RELATED_NUM and
RELATED_TEXT for details
REWRITE_FULL_TEXT_MATCH --N-- query rewrite is disabled on the
materialized view
REWRITE_PARTIAL_TEXT_MATCH --N-- materialized view cannot support
any type of query rewrite
REWRITE_PARTIAL_TEXT_MATCH --N-- query rewrite is disabled on the
materialized view
REWRITE_GENERAL --N-- materialized view cannot support any type of
query rewrite
REWRITE_GENERAL --N-- query rewrite is disabled on the materialized
view
REWRITE_PCT --N-- general rewrite is not possible or PCT is not
possible on an
PCT_TABLE_REWRITE --N-- Oracle error: see RELATED_NUM and
RELATED_TEXT for details
How can I achieve Fast Refresh On Commit ?
The Oracle Version details are as follows:
NLSRTL 10.2.0.4.0 Production
Oracle Database 10g 10.2.0.4.0 64bit Production
PL/SQL 10.2.0.4.0 Production
TNS for Linux: 10.2.0.4.0 Production
I don't know if the problem still persists, but as I took a look at the artice you provided, I noticed something (which might just be the solution here):
ON COMMIT Refresh
A materialized view can be refreshed automatically using the ON COMMIT method. Therefore, whenever a transaction commits which has updated the tables on which a materialized view is defined, those changes are automatically reflected in the materialized view. The advantage of using this approach is you never have to remember to refresh the materialized view. The only disadvantage is the time required to complete the commit will be slightly longer because of the extra processing involved. However, in a data warehouse, this should not be an issue because there is unlikely to be concurrent processes trying to update the same table.
Notice the bold line.
Then we have:
Table 7-1 ON DEMAND Refresh Methods
Refresh Option Parameter Description
COMPLETE C Refreshes by recalculating the defining query of the materialized view.
FAST F Refreshes by incrementally applying changes to the materialized view. For local materialized views, it chooses the refresh method which is estimated by optimizer to be most efficient. The refresh methods considered are log-based FAST and FAST_PCT.
FAST_PCT P Refreshes by recomputing the rows in the materialized view affected by changed partitions in the detail tables.
FORCE ? Attempts a fast refresh. If that is not possible, it does a complete refresh.
For local materialized views, it chooses the refresh method which is estimated by optimizer to be most efficient. The refresh methods considered are log based FAST, FAST_PCT, and COMPLETE.
Notice the bold lines.
I personally prefer the FORCE Option.
Could you please tell, if this occurs again after some time (depending of the parameters of the DB and the machine it runs on, so I can't even hint you how much)?
When Fast Refresh is Possible
Not all materialized views may be fast refreshable. Therefore, use the package DBMS_MVIEW.EXPLAIN_MVIEW to determine what refresh methods are available for a materialized view.
If you are not sure how to make a materialized view fast refreshable, you can use the DBMS_ADVISOR.TUNE_MVIEW procedure, which provides a script containing the statements required to create a fast refreshable materialized view.
Cheers
I see that you created the materialized view logs with ROWID, which is not really required as both tables have a primary key so you could try without the ROWID.
create materialized view log on emp;
create materialized view log on dept;
Additionally, if you create the materialized view log with ROWID you should create the materialized view with rowid.
create materialized view empdept_mv refresh fast on commit WITH ROWID as
select a.rowid dept_rowid, b.rowid emp_rowid, a.dept_no,b.emp_no
from dept a, emp b
where a.dept_no=b.dept_no ;
You could try those changes and see if the materialized views fast refresh on commit.
Related
please help me with an example on how to add primary key to materialized view in oracle 19c or 21c.
Also, real life application where we use primary key to materialized view. I posting this after complete research on materialized view.
I have a strong opinion that primary key is not required on materialized view. Please correct me if I am wrong.
How to add a primary key? Using the ALTER TABLE statement.
This is a sample table; I'll create a materialized view on it.
SQL> create table test as
2 select deptno, empno, ename, job
3 from emp;
Table created.
SQL> create materialized view mv_test as
2 select deptno, empno, ename, job
3 from test;
Materialized view created.
Primary key:
SQL> alter table mv_test add constraint pk_mvt primary key (empno);
Table altered.
SQL>
Real life: use it whenever appropriate. Primary key implicitly creates index on primary key column(s). Index improves performance (if optimizer chooses to use it).
I'm using Oracle and I have a strange thing.
I dropped a table using :
drop table t_my_table, and committed.
But when I launch select * from t_my_table, it shows the data, as if the table is not dropped.
I tried disconnecting and reconnecting, it stills shows the data when I select.
And when I once again try with :
drop table t_my_table, it tells me that this table does not exist.
But if I run select again, the data is always there.
How is this possible ?
Thank you.
You mean this case?
create view t_my_table as
select 'I''m here' as txt from dual;
drop table t_my_table;
ORA-00942: table or view does not exist
But
select * from t_my_table;
TXT
--------
I'm here
solution of the most probably cause
select OBJECT_TYPE from user_objects where object_name = 'T_MY_TABLE';
OBJECT_TYPE
-------------------
VIEW
You defined a view (or other object type other than TABLE), that can't be dropped with DROP TABLE, but can be selected.
Simple check in USER_OBJECTS the OBJECT_TYPE. You may alternatively see also SYNONYM as proposed in other answer.
Note that it is not a MATERIALIZED VIEW as if you try to drop a Materialized View with DROP TABLE a different error message is raised:
ORA-12083: must use DROP MATERIALIZED VIEW to drop T_MY_TABLE
What does this return?
select * from all_synonyms
where synonym_name = 'T_MY_TABLE';
I suspect there is a synonym T_MY_TABLE that points to a table in a different schema.
drop table t_my_table purge;
Specify PURGE if you want to drop the table and release the space associated with it in a single step. If you specify PURGE, then the database does not place the table and its dependent objects into the recycle bin.
...
Using this clause is equivalent to first dropping the table and then purging it from the recycle bin. This clause lets you save one step in the process. It also provides enhanced security if you want to prevent sensitive material from appearing in the recycle bin.
Probably something different is happening.
Normal case would be:
SQL> create table t1 as select 1 a from dual;
Table T1 created.
SQL> drop table t1;
Table T1 dropped.
SQL> select * from t1;
Error starting at line : 22 in command -
select * from t1
Error at Command Line : 22 Column : 20
Error report -
SQL Error: ORA-00942: table or view does not exist
00942. 00000 - "table or view does not exist"
*Cause:
*Action:
So what was the message after the drop table?
Is t_my_table really a table?
Try select * from all_objects where lower(object_name) = 't_my_table'
I would like to have more than one materialized view with refresh fast on commit.
For "refresh fast on commit" you need a materialized view log. Obviously a refresh fast on commit needs the log. The question is can I have more than one materialized view accessing the log.
Obviously I still need the log to satisfy the normal prerequisites (across all views):
http://docs.oracle.com/cd/B19306_01/server.102/b14223/basicmv.htm
Cheers for any help in advance.
Absolutely.
create table data_table as (
select *
from dba_users
);
alter table data_table
add constraint data_table_test_pk PRIMARY KEY (user_id);
select * from data_table;
So now we have a table that looks like dba_users with a PRIMARY KEY constraint.
create materialized view log on data_table;
create materialized view mat_view_one
refresh fast on commit
as
select username, user_id
from data_table
;
create materialized view mat_view_two
refresh fast on commit
as
select user_id, username, account_status
from data_table;
There's our log and the 2 views create successfully.
SYS record in the test table:
select * from mat_view_one
where user_id=0;
USERNAME USER_ID
------------------------------ ----------
SYS 0
select * from mat_view_two
where user_id=0;
USER_ID USERNAME ACCOUNT_STATUS
---------- ------------------------------ --------------------------------
0 SYS OPEN
Now lets update the SYS's name and commit and see what our views show:
update data_table
set username='WALTERWHITE'
WHERE USER_ID=0
;
COMMIT;
USERNAME USER_ID
------------------------------ ----------
WALTERWHITE 0
USER_ID USERNAME ACCOUNT_STATUS
---------- ------------------------------ --------------------------------
0 WALTERWHITE OPEN
So yes, absolutely. 1 materialized view log can serve as many materialized views as you need so long as the proper constraints are held.
Yes. A materialized view log can support as many materialized views as you'd like.
Supporting multiple materialized views may cause the log to be larger than it would be if it was supporting a single materialized view though that probably isn't terribly significant here since your logs probably won't store the data long. If you're replicating data to remote databases (which by definition you can't do with a fast refreshable materialized view), it can be a bit tricky if one of the remote materialized views stops refreshing or goes away without the source being aware since it can cause data to queue up indefinitely in the log. But, again, that doesn't sound like the situation you're facing.
I'm confused about Materialized views. Either it is the Toad IDE that I am using that is confusing me, or its that I don't understand MVs enough.
I created a materialized view in Oracle by something like this....
CREATE MATERIALIZED VIEW TESTRESULT
NOCACHE
LOGGING
NOCOMPRESS
NOPARALLEL
BUILD IMMEDIATE
REFRESH FORCE ON DEMAND
WITH PRIMARY KEY
AS
SELECT ...
FROM tables...
I would expect that the materialized view would be created and populated with the data returned from the query. Okay, not a big deal.
What I am confused on is why my Toad IDE shows a table 'TESTRESULT' under the tables section. It even has a 'Create Table Script' that I can look at.
But I also see my materialized view under the 'Materialized View' section.
Behind the scenes is Oracle creating a table when I create a materialized view? It looks as if there are two seperate objects, a materialized view and a table? Could someone please explain what is going on here behind the scenes when creating a materialized view? Is Toad wrong or am I misunderstanding something?
Toad version: 9.6.1.1
Oracle: 10g
Yes, behind the scenes, Oracle creates two objects, a table where the results are actually materialized and a materialized view that has all the metadata (the query, the attributes, etc.). It's very similar to what happens when you create a unique constraint-- Oracle creates a unique index with the same name as the constraint to actually enforce the constraint and then it creates a constraint itself. If you create a materialized view on a pre-built table, you can end up with different names for the table and for the materialized view just as you could create a constraint that uses an existing index that has a different name.
SQL> select object_name, object_type
2 from user_objects
3
SQL> ed
Wrote file afiedt.buf
1 select object_name, object_type
2 from user_objects
3* where object_name = 'MV_EMP'
4 /
no rows selected
SQL> create materialized view mv_emp
2 as
3 select *
4 from emp;
Materialized view created.
SQL> column object_name format a30;
SQL> select object_name, object_type
2 from user_objects
3 where object_name = 'MV_EMP';
OBJECT_NAME OBJECT_TYPE
------------------------------ -------------------
MV_EMP TABLE
MV_EMP MATERIALIZED VIEW
I have a materialized view defined this way:
CREATE MATERIALIZED VIEW M_FOO
REFRESH COMPLETE ON COMMIT
AS
SELECT FOO_ID, BAR
FROM FOO
WHERE BAR IS NOT NULL
GROUP BY FOO_ID, BAR
/
COMMENT ON MATERIALIZED VIEW M_FOO IS 'Foo-Bar pairs';
I wrote as a sort of cache: the source table is huge but the number of different pairs is fairly small. I need those pairs to get them JOINed with other tables. So far so good: it absolutely speeds queries.
But I want to make sure that the view does not contain obsolete data. The underlying table is modified four or five times per month but I don't necessarily know when. I understand that a materialized view can be defined so it updates when the source tables change. However, the docs get pretty complicate.
What's the exact syntax I need to
use?
Do I need to create a materialized
view log?
What's the difference between fast
and complete refresh?
To take your questions in reverse order
A FAST refresh is also known as an incremental refresh. That should give you a clue as to the difference. A COMPLETE refresh rebuilds the entire MVIEW from scratch, whereas a FAST refresh applies just the changes from DML executed against the feeder table(s).
In order to do execute FAST refreshes you need the appropriate MVIEW LOG. This tracks changes to the data of the underlying tables, which allows Oracle to efficiently apply a delta to the materialized view, rather than querying the whole table.
As for the syntax, here are the basics:
SQL> create materialized view log on emp
2 with rowid, primary key, sequence (deptno, job)
3 including new values
4 /
Materialized view log created.
SQL> create materialized view emp_mv
2 refresh fast on commit
3 as
4 select deptno, job from emp
5 group by deptno, job
6 /
Materialized view created.
SQL>
The ON COMMIT clause means that the MVIEW is refreshed transactionally (as opposed to ON DEMAND which is regular refresh in bulk). The REFRESH clauses specifies whether to apply incremental or complete refreshes. There are some categories of query which force the use of COMPLETE refresh, although these seem to diminish with each new version of Oracle.
A quick test to see that it works ...
SQL> select * from emp_mv
2 order by deptno, job
3 /
DEPTNO JOB
---------- ---------
10 MANAGER
10 PRESIDENT
10 SALES
20 ANALYST
20 CLERK
20 MANAGER
30 CLERK
30 MANAGER
30 SALESMAN
40 CLERK
40 DOGSBODY
11 rows selected.
SQL>
How about a new record?
SQL> insert into emp (empno, ename, deptno, job)
2 values (6666, 'GADGET', 40, 'INSPECTOR')
3 /
1 row created.
SQL> commit
2 /
Commit complete.
SQL> select * from emp_mv
2 order by deptno, job
3 /
DEPTNO JOB
---------- ---------
10 MANAGER
10 PRESIDENT
10 SALES
20 ANALYST
20 CLERK
20 MANAGER
30 CLERK
30 MANAGER
30 SALESMAN
40 CLERK
40 DOGSBODY
40 INSPECTOR
12 rows selected.
SQL>
You can find more details on the syntax in the SQL Reference. It's also worth reading the Materialized View chapter in the Data Warehousing Guide.
Despite the concerns of the commenters below this does work as advertised. Unfortunately the usual places for publishing demos (SQL Fiddle, db<>fiddle) do not allow materialized views. I have published something on Oracle SQL Live (free Oracle account required): I am awaiting Oracle approval for it and will update this question when it arrives.
A fast refresh will only insert/update/delete changed data into the materialized view. A complete refresh will empty the materialized view and then copy over all rows.
The "on commit" means the materialized view will be refreshed whenever a change is committed in the master table. So your current syntax is going to be extremely inefficient. Every time somebody changes any row in foo, m_foo will be truncated and then every row in foo table will be inserted.
You can do better with fast refreshes, where only the modified rows in foo will be sent to m_foo. That gives you consistency without lots of overhead.
create materialized view log on foo with primary key; -- assuming you have a primary key, you should
create materialized view m_foo refresh fast on commit as \;
There are some additional subtleties with grants and synonyms if you're using db links, or the schema that owns foo isn't the one that owns m_foo.