MView "enable query rewrite" usage - oracle

CREATE TABLE TEST_DATE(COL1 VARCHAR2(20),COL2 NUMBER,COL3_DATE DATE,COL4_DATE DATE)
/
create materialized view TEST_SYS
REFRESH FORCE ON DEMAND
ENABLE QUERY REWRITE --- ????
AS
SELECT COL1,COL2
FROM TEST_date
WHERE TRUNC(SYSDATE) BETWEEN TRUNC(COL3_DATE) AND TRUNC(COL4_DATE)
/
If Enable Query Rewrite option is disabled, MView is getting created for the above query then what is the purpose of having ENABLE QUERY REWRITE clause while creating materialized view, can we remove it and create it, and do we have to compromise on the performance of the MView if we have to comment Enable Query Rewrite.
Please explain me the use of enable query rewrite option in detail.

Query rewrite allows Oracle to rewrite a query against the base table (in this case TEST_DATE) to use the materialized view (in this case TEST_SYS) transparently. That is highly useful when your materialized view is pre-aggregating data, for example. If I have a transactions table and a materialized view
CREATE MATERIALIZED VIEW mv_transaction_daily
REFRESH FORCE ON DEMAND
ENABLE QUERY REWRITE
AS
SELECT store_id,
transaction_day,
SUM(transaction_amount) total_transaction_amount
FROM transactions
GROUP BY store_id, transaction_day
then Oracle could transform a query like
SELECT store_id,
transaction_day,
SUM(transaction_amount) total_transaction_amount
FROM transactions
GROUP BY store_id, transaction_day
to use the materialized view rather than hitting the base table. And if you have appropriate dimension objects created, you could have a query like
SELECT store_id,
trunc(transaction_day,'MM'),
SUM(transaction_amount) monthly_transaction_amount
FROM transactions
GROUP BY store_id, trunc(transaction_day,'MM')
that could also be rewritten to use the materialized view rather than the base table.
If query rewrite is not enabled, you would only see a performance benefit from using the materialized view if you explicitly queried the materialized view rather than querying the base table. That generally requires more development effort and limits the ability of the DBAs to tune the application in the future by fine-tuning materialized views.
In your case, the presence of SYSDATE in your WHERE clause is going to prevent query rewrite because Oracle wouldn't be able to figure out that a query against TEST_DATE would actually be able to use the materialized view. For all Oracle knows, data in the materialized view that satisfied the condition when the materialized view was refreshed no longer satisfies the condition and data that didn't make it into the materialized view now satisfies the condition simply because the SYSDATE has changed.

You do not need to have query rewrite enabled. Further, given your mview definition, it probably wouldn't hep you anyway.

Related

Oracle - Refresh complex materialized view in trigger?

I'm trying to accomplish materialized view refresh after updates on any of source tables. Materialized view DDL looks like this:
CREATE MATERIALIZED VIEW EMPLOYEES_GROUPS_FLAT
CACHE AS
SELECT UNIQUE end_groups AS group_id,employee_id
FROM (
SELECT group_id AS end_group,CONNECT_BY_ROOT group_id AS root_group
FROM privilege_groups
START WITH group_id IN (SELECT group_id FROM employees_groups)
CONNECT BY PRIOR parent_group_id=group_id
)
RIGHT JOIN employees_groups ON (root_group=group_id)
I tried to use ON COMMIT rebuild but it seems it doesn't support nested select. In general this query looks quite complex for fast update on commit. I also tried triggers but they don't seem to include recently added value. I don't have database permissions to use job scheduling. Is there anything else I can do?

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.

Redefine materialized view with no downtime

I have a materialized view that I need to redefine the SQL for. We have an external system that hits the view over a db link, and the monster view takes 5 minutes to refresh the data in the view. The only way I know how to redefine the SQL for a view is to drop it and recreate it, but it would be very bad if the external system couldn't find the table, or it didn't have a complete data set. I need to have as little downtime as possible.
Is there any way to do this natively or more elegantly than:
Create public synonym for materialized view and make everything that uses the view use the synonym instead.
Create new materialized view with new SQL
Change the synonym to point to the new view
Drop the old view.
I've got code to do this dynamically but it is getting really ugly. It seems like there should be a better way to handle this.
Oracle has a build in solution for that. Keep in mind that the mview declaration is separate from that of the table.
The original mview
create materialized view mv1 as select dept , count(*) as cnt from scott.emp;
we want to change the declaration so that only dept over 5 will be calculated
drop materialized view mv1 preserve table;
notice the PRESERVE TABLE clause - the table mv1 is not droped - only the mview layer.
desc mv1
now we create the mview with a different query on top of the existing table
create materialized view mv1 on prebuilt table as
select dept , count(*) as cnt from scott.emp where dept > 5;
notice the on prebuilt table clause. the mview is using the existing object.
exec dbms_mview.refresh_mview('mv1');

Query too complex for a simple join [duplicate]

So I'm pretty sure Oracle supports this, so I have no idea what I'm doing wrong. This code works:
CREATE MATERIALIZED VIEW MV_Test
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT V.* FROM TPM_PROJECTVERSION V;
If I add in a JOIN, it breaks:
CREATE MATERIALIZED VIEW MV_Test
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT V.*, P.* FROM TPM_PROJECTVERSION V
INNER JOIN TPM_PROJECT P ON P.PROJECTID = V.PROJECTID
Now I get the error:
ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view
I've created materialized view logs on both TPM_PROJECT and TPM_PROJECTVERSION. TPM_PROJECT has a primary key of PROJECTID and TPM_PROJECTVERSION has a compound primary key of (PROJECTID,VERSIONID). What's the trick to this? I've been digging through Oracle manuals to no avail. Thanks!
To start with, from the Oracle Database Data Warehousing Guide:
Restrictions on Fast Refresh on Materialized Views with Joins Only
...
Rowids of all the tables in the FROM list must appear in the SELECT
list of the query.
This means that your statement will need to look something like this:
CREATE MATERIALIZED VIEW MV_Test
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT V.*, P.*, V.ROWID as V_ROWID, P.ROWID as P_ROWID
FROM TPM_PROJECTVERSION V,
TPM_PROJECT P
WHERE P.PROJECTID = V.PROJECTID
Another key aspect to note is that your materialized view logs must be created as with rowid.
Below is a functional test scenario:
CREATE TABLE foo(foo NUMBER, CONSTRAINT foo_pk PRIMARY KEY(foo));
CREATE MATERIALIZED VIEW LOG ON foo WITH ROWID;
CREATE TABLE bar(foo NUMBER, bar NUMBER, CONSTRAINT bar_pk PRIMARY KEY(foo, bar));
CREATE MATERIALIZED VIEW LOG ON bar WITH ROWID;
CREATE MATERIALIZED VIEW foo_bar
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT AS SELECT foo.foo,
bar.bar,
foo.ROWID AS foo_rowid,
bar.ROWID AS bar_rowid
FROM foo, bar
WHERE foo.foo = bar.foo;
Have you tried it without the ANSI join ?
CREATE MATERIALIZED VIEW MV_Test
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT V.*, P.* FROM TPM_PROJECTVERSION V,TPM_PROJECT P
WHERE P.PROJECTID = V.PROJECTID
You will get the error on REFRESH_FAST, if you do not create materialized view logs for the master table(s) the query is referring to. If anyone is not familiar with materialized views or using it for the first time, the better way is to use oracle sqldeveloper and graphically put in the options, and the errors also provide much better sense.
The key checks for FAST REFRESH includes the following:
1) An Oracle materialized view log must be present for each base table.
2) The RowIDs of all the base tables must appear in the SELECT list of the MVIEW query definition.
3) If there are outer joins, unique constraints must be placed on the join columns of the inner table.
No 3 is easy to miss and worth highlighting here
USE THIS CODE
CREATE MATERIALIZED VIEW MV_ptbl_Category2
BUILD IMMEDIATE
REFRESH FORCE
ON COMMIT
AS
SELECT *
FROM ptbl_Category2;
Note- MV_ptbl_Category2 is the Materialized view name
Ptbl is the table name.

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