Oracle materialized view computational cost - oracle

Is the computational cost of updating a stored procedure materialized view, in Oracle, based on the query execution or the result set? More specifically, does Oracle store the results of the query in such a way that contributes significantly to the time required to refresh the view?
Of course, queries which take very long to execute as well as incredibly large or small result sets make this impossible to answer ubiquitously.
The question is more about how the view actually stores the result set (in memory, on disk) so I can think about how frequently to rebuild materialized views.

Materialized view is basically a table combined with an algorithm to update it.
01:37:23 HR#sandbox> create materialized view mv_dual as select dummy from dual;
Materialized view created.
Elapsed: 00:00:00.52
01:37:56 HR#sandbox> select object_name, object_type from user_objects where object_name = 'MV_DUAL';
OBJECT_NAME OBJECT_TYPE
--------------- -------------------
MV_DUAL TABLE
MV_DUAL MATERIALIZED VIEW
Elapsed: 00:00:00.01
You can also create materialized views on prebuilt tables.
If we talk about refresh - there are two options: fast refresh and complete refresh.
Complete refresh just re-executes MV query, while fast refresh performs incremental updates.
http://docs.oracle.com/cd/E16338_01/server.112/e10706/repmview.htm#i29858

there are two types of mviews
Complete refresh mview - the entier mview will be rebuild every refresh. similar to delete and insert (notice: if you specify atomic = F or have version < 9 it will be truncate / insert append).
Fast refresh mview - oracle will create a table to store incremental changes. when refreshing, the changes stored in the side table will be applied to the mview.
fast refresh is faster on refresh but slows down dml operations on the base table.
when you consider your refresh strategy you should consider how much changes are applied to the base table and how often you need to refresh the mview.

Related

Are materialized views virtual tables or real tables with real data?

When materialized views are created in Oracle, do they store indices or do they store actual table values?
I am asking this as creating index on table and using views on that table and using materialized views (created with refresh complete start with (sysdate) next (sysdate+1) with rowid as) on unindexed table gives similar performance.
Where as I would expect materialized views to be far more faster.
Update
I slightly modified the content/title. My current concern after discussion is if materialized views are actual real tables or virtual tables with some optimization.
Materialized views create a copy of the data. To all intents and purposes they are actual tables. In fact we can create a materialized view from an existing table using the PREBUILT clause. The only difference is how the data is mastered - a materialized view doesn't own its data, a table does.
As to your performance conundrum:
When you say "on unindexed table" do you literally mean one table? If so, we wouldn't expect any difference in the time to query a view, a materialized view or the actual data: they all execute a full table scan on the same volume of data.
Consider the case where views have expecting select * from <table> where <condition>.
We would a SELECT against a materialised view built on that query to execute quicker than the same SELECT against the actual table, provided the WHERE clause restricts the data to a significantly smaller subset of the original data. Simply because a full table scan over a small table (materialised view) takes less time than a full table scan over a big table. Same applies if the materialised view's projection has fewer columns than the base table.
Indexing is a different matter. Unless the query selects a very small subset of the data it's not going to be more efficient than a full table scan and a filter.
To sum up: the only universal tuning heuristic is: it takes less time to do less work. Beyond that it is impossible to generalise. We can't discuss some vague "consider the case where views have select * from <table> where <condition>." It's all about the specifics.
Fundamentally, a materialized view is just a table with an associated query to populate it.
Given static data, one would generally expect the performance of a SELECT * from the materialized view (with no WHERE clause) to be at least as fast as running the query that underlies the materialized view, regardless of indexing.
If we add a WHERE clause to a SELECT * against the mview, however, that query could perform significantly slower than running the query that underlies the mview with the same WHERE clause. That's because the tables referenced in the query underlying the mview could have indexes to support the conditions in the WHERE clause, where as the mview might not have such indexes.

Can Materialized View fast refresh work when based on views are based on tables?

I am reviewing my team's database setup, particularly focusing on Materialized Views. In most cases, we are currently doing 'Complete' refreshes, and I want to move to doing fast refreshes.
In some cases, this is straight forward -- the MV is based directly on a table on our source database, and I can enable MVIEW LOGS on the table and recreate the MV.
But in a number of cases, the MVs are based on a combination of other MVs, and Views, etc, that go several levels deep before I get to the tables on our source database.
In these cases, if I track down the ultimate source tables, will enabling MVIEW LOGS on them allow the top MV and any intermediate MVs, to use fast refresh?
The Oracle documentation contains an example for a FAST REFRESH of a materialized view based on an UNION ALL view:
CREATE VIEW view_with_unionall AS
(SELECT c.rowid crid, c.cust_id, 2 umarker
FROM customers c WHERE c.cust_last_name = 'Smith'
UNION ALL
SELECT c.rowid crid, c.cust_id, 3 umarker
FROM customers c WHERE c.cust_last_name = 'Jones');
CREATE MATERIALIZED VIEW unionall_inside_view_mv
REFRESH FAST ON DEMAND AS
SELECT * FROM view_with_unionall;
So in principle, you can indeed fast refresh materialized views based on views.
Some things to note:
there are a couple of restrictions for fast refreshable materialized views. E.g. you cannot use ROWNUM, SYSDATE or HAVING. See the docs for details
somewhat counterintuitively, a FAST REFRESH is not always faster than a COMPLETE REFRESH. This depends on the amount of data that has changed since the last refresh; IMHO, Oracle should have used the term INCREMENTAL REFRESH instead
Oracle provides a procedure for that: DBMS_MVIEW.EXPLAIN_MVIEW
You can use this procedure to check whether your Materialized Views is capable for FAST REFRESH, it also tells you the reason why it is not.
For me the most strange restriction for FAST REFRESH is: When you join several tables you have to use the (old) Oracle Join syntax, ANSI join syntax does not work. Some time ago a created a case at Oracle support for this issue, however the answer from Oracle was: "This is not a bug, it is just a lack of documentation."(!)
I don't know if it still applies for Oracle 12c version.

Materialized View Refresh with changing synonym pointer in SQL

I have two tables, TABLE_1 and TABLE_2. Then we have a synonym called TABLE that points to either TABLE_1 or TABLE_2. When TABLE_1 is active, an ETL populates TABLE_2 and when the run is complete, it switches the TABLE synonym to TABLE_2 to make it the active table. Then I have a materialized view that does something like this as the SQL: select * from TABLE. What I am seeing happen is that after the materialize view runs the first time, it caches the actual table the synonym is pointing too. So when the ETL runs and flips the synonym to point at TABLE_2, when a complete refresh is done on the materialized view, it still thinks the synonym is pointed at TABLE_1. Why when I do a complete refresh does the materialized view not pick up the new synonym pointer to TABLE_2?
Here is a workaround to Oracle's bug:
alter materialized view MV_NAME nocache;
BEGIN DBMS_SNAPSHOT.REFRESH( MV_NAME,'C'); end;
alter materialized view MV_NAME cache;
I cannot find anything useful in Oracle documentation but just enable the logic:
I firstly create materialized view
In reality to support this materialized view Oracle makes the TABLE with some specific structure (dependent on your query structure) and the rule to refresh the table (as far as I remember it is called SUMMARY, but the name does not play any role here)
I change synonym target to the table which has another structure
The new target table is not "fitting" to the previous structure (e.g. it has totally different amount/data types of columns), the previous structure is invalid then and not working anymore. The underground table must be recreated then.
That's why I would say it is the only way to prevent the errors: reference the real target instead of synonym for creating materialized view.
So, the answer is: because the materialized view is a static table-like object dependent on the data set it is selecting; that's why to prevent the inconsistencies materialized view references the real object.
Sometimes I really wonder how many details Oracle hides inside.

Why does a ORA-12054 error occur when creating this simple materialized view example?

ALTER TABLE RECORDINGS ADD PRIMARY KEY (ID);
CREATE MATERIALIZED VIEW LOG ON RECORDINGS TABLESPACE USERS NOLOGGING;
DROP MATERIALIZED VIEW REC_SEARCH_TEST;
CREATE MATERIALIZED VIEW REC_SEARCH_TEST
REFRESH COMPLETE ON COMMIT
AS (
SELECT DISTINCT ID, TITLE FROM RECORDINGS
);
ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view
Cannot understand what is wrong here, I know that if I take out the DISTINCT clause it works, but why can I not use 'DISTINCT' if I specify 'REFRESH COMPLETE ON COMMIT' which is required.
If I use DISTINCT and REFRESH on demand there is no problem, but these are not the requirements.
Seems like with the addition of the DISTINCT, you've made your view's underlying SQL ineligible for fast refresh, and therefore not able to be used with ON COMMIT (even tho you specify refresh complete instead of refresh fast). From Oracle docs:
The two refresh execution modes are ON COMMIT and ON DEMAND. Depending
on the materialized view you create, some of the options may not be
available. Table 8-4 describes the refresh modes.
Table 8-4 Refresh Modes
ON COMMIT
Refresh occurs automatically when a transaction that modified one of
the materialized view's detail tables commits. This can be specified
as long as the materialized view is fast refreshable (in other words,
not complex). The ON COMMIT privilege is necessary to use this mode.
ON DEMAND
Refresh occurs when a user manually executes one of the available
refresh procedures contained in the DBMS_MVIEW package (REFRESH,
REFRESH_ALL_MVIEWS, REFRESH_DEPENDENT).
The same document link has a list of restrictions for fast refresh as well.
"Perhaps the example isn't the best, because I want to expand the view
to a more complicated query that will require a distinct keyword,
right now I am just trying to get it working on a basic level. "
The DISTINCT is the cause of the ORA-12054.
SQL> CREATE MATERIALIZED VIEW REC_SEARCH_TEST
REFRESH COMPLETE ON COMMIT
AS (
SELECT DISTINCT empno, ename FROM emp
)
/
2 3 4 5 6
SELECT DISTINCT empno, ename FROM emp
*
ERROR at line 4:
ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view
Elapsed: 00:00:01.14
SQL> SQL>
SQL> CREATE MATERIALIZED VIEW REC_SEARCH_TEST
REFRESH COMPLETE ON COMMIT
AS (
SELECT empno, ename FROM emp
)
/
2 3 4 5 6
Materialized view created.
Elapsed: 00:00:02.33
SQL>
Why not start with a something that works? Remove the DISTINCT. Get your MView working. Then complicate it later when it becomes necessary.
Although, as you already know you cannot use a DISTINCT you will have to revise either your query's logic or your refresh strategy.
The important thing to note about the question is that it is not about fast refresh, but complete refresh. Thus, there is no logical reason that the usual restrictions for fast refresh on commit should apply, except the one that all referenced objects must be local.
The "refresh complete on commit is a relatively new feature, so the best answer to the "why" question is probably "Oracle has not yet implemented this fully, please check future versions of Oracle Database". Not very useful, but true...

Oracle materialized view question

I have a table that holds information about different events, for example
CREATE TABLE events (
id int not null primary key,
event_date date, ...
)
I realized that 90% of all queries access only today events; the older rows are stored for history and eventually moved to an archive table.
However, events table is still large, and I wonder if I can improve the performance by creating a materialized view that has something like WHERE event_date = trunc(sysdate) and maybe index on event_date ? Is it allowed at all?
Thanks
yes this is allowed see "primary key materialized view":
Primary key materialized views may contain a subquery so that you can
create a subset of rows at the remote materialized view site
and "complex materialized view"
If you refresh rarely and want faster query performance, then use
Method A (complex materialized view).
If you refresh regularly and can sacrifice query performance, then use Method B (simple materialized view).
at http://download.oracle.com/docs/cd/B10500_01/server.920/a96567/repmview.htm
In your example chances are good IMHO that this is not a "complex materialized view":
CREATE MATERIALIZED VIEW events_today REFRESH FAST AS
SELECT * FROM EVENT WHERE event_date = trunc(sysdate);
Just try it and see if Oracle accepts it with the REFRESH FAST clause.
EDIT - another option:
Depending on your DB Edition (Enterprise + Partitioning) and Version (11gR2) you could use a new Oracle feature called INTERVAL partitioning to define "daily partitions" within the existing table. This way most of your queries get alot faster without effectively duplicating the data - see http://www.oracle.com/technetwork/database/options/partitioning/twp-partitioning-11gr2-2009-09-130569.pdf

Resources