I have a materialized view that looks somewhat like the following and I'm wondering if there is anyway to have this materialized view 'fast' refreshable? Basically, I'm asking the following:
Can a materialized view contain oracle functions such as COALESCE, NVL, NVL2, etc and still be fast refreshable
Can a materialized view contain functions that I have made and still be fast refreshable.
Can a materialized view contain joins to derived tables and still be fast refreshable?
I checked the Oracle documentation about this, and it did not list these restrictions, however after testing the case below on my own system, I don't believe it is possible.
Oracle version: 10g
SELECT COALESCE (col1, col2),
myOracleFunction(col3, col4)
FROM tableA a
LEFT OUTER JOIN
(SELECT id, MAX (sample_key) prim_sam_key
FROM table_sample
GROUP BY id
HAVING COUNT (1) = 1) b ON a.id = b.id;
Requirements from the link you provided that you're missing:
COUNT(*) must be specified.
The SELECT list must contain all GROUP BY columns.
Also, the following requirement indicates that, for your query, a fast refresh will only be possible if table_sample has been updated, but tableA has not:
Materialized aggregate views with outer joins are fast refreshable
after conventional DML and direct loads, provided only the outer table
has been modified. Also, unique constraints must exist on the join
columns of the inner join table. If there are outer joins, all the
joins must be connected by ANDs and must use the equality (=)
operator.
Finally, when asking about materialized views, it is always a good idea to state exactly what materialized view logs you have created.
Related
I'm trying to create a Real Time Materialized View. My Query contains Left Outer Joins. These Left outer Joins did not let me use ENABLE ON QUERY COMPUTATION feature of Real Time Materialized View. I replaced joins with UNION that also is not executable with ENABLE ON QUERY COMPUTATION. Does any one has any idea how to get pass it?
My Sample Query:
CREATE MATERIALIZED VIEW “MV_XYZ”
(set of columns names associated with the parent tables used to
create MV)
REFRESH FAST ON DEMAND
ENABLE QUERY REWRITE
ENABLE ON QUERY COMPUTATION
AS select "set of values associated from these 4 tables"
FROM abc_set ds, abc_d d
LEFT OUTER JOIN ab_case dc ON dc.c_id = d.id
LEFT OUTER JOIN abc_lab dl ON dl.l_id = d.id
WHERE ds.id = d.d_id
AND d.ch = 1
AND ds.type = ‘ARC’;
I also have a MV_log for the above MV so that I can have real time data using FRESH_MV hint feature of 12.2 version
And Error I get
ORA-32361: cannot ENABLE ON QUERY COMPUTATION for the materialized view
One issue could be MV logs is not created for all the base tables. From Oracle docs:
Ensure that materialized view logs exist on all the base tables of the real-time materialized view.
I have encountered the same issue ORA-32361 when i was using only the static columns like below:
CREATE MATERIALIZED VIEW EMP_DEPT_MV
REFRESH FAST ON DEMAND
ENABLE QUERY REWRITE
ENABLE ON QUERY COMPUTATION
AS
select e.deptno,e.SAL from emp e LEFT JOIN dept d on d.deptno = e.deptno;
ORA-32361: cannot ENABLE ON QUERY COMPUTATION for the materialized view
But when I added the aggregate columns, it worked without issues
CREATE MATERIALIZED VIEW EMP_DEPT_MV
REFRESH FAST ON DEMAND
ENABLE QUERY REWRITE
ENABLE ON QUERY COMPUTATION
AS
select e.deptno,sum(SAL) from emp e LEFT JOIN dept d on d.deptno = e.deptno
group by e.deptno;
For more info please refer Using Real-time Materialized Views
I have created a materialized view with Refresh complete like that and it works well:
CREATE MATERIALIZED VIEW VM4
Build immediate
refresh complete on commit
AS
select C.codecomp,
count(c.numpolice) as NbContrat,
SUM(c.montant) as MontantGlobal
from contrat C
group by c.codecomp;
Now I would like to create a similar view but with Refresh Fast but it dosn't work and it shows me this error:
error
Knowing that I have already created the LOG of the Contrat table ilke that:
CREATE MATERIALIZED VIEW LOG ON contrat with rowid ;
Check documentation:
General Restrictions on Fast Refresh
The defining query of the materialized view is restricted as follows:
The materialized view must not contain references to non-repeating expressions like SYSDATE and ROWNUM.
The materialized view must not contain references to RAW or LONG RAW data types.
It cannot contain a SELECT list subquery.
It cannot contain analytic functions (for example, RANK) in the SELECT clause.
It cannot reference a table on which an XMLIndex index is defined.
It cannot contain a MODEL clause.
It cannot contain a HAVING clause with a subquery.
It cannot contain nested queries that have ANY, ALL, or NOT EXISTS.
It cannot contain a [START WITH …] CONNECT BY clause.
It cannot contain multiple detail tables at different sites.
ON COMMIT materialized views cannot have remote detail tables.
Nested materialized views must have a join or aggregate.
Materialized join views and materialized aggregate views with a GROUP BY clause cannot select from an index-organized table.
Restrictions on Fast Refresh on Materialized Views with Aggregates
Defining queries for materialized views with aggregates or joins have
the following restrictions on fast refresh:
All restrictions from "General Restrictions on Fast Refresh".
Fast refresh is supported for both ON COMMIT and ON DEMAND
materialized views, however the following restrictions apply:
All tables in the materialized view must have materialized view logs, and the materialized view logs must:
Contain all columns from the table referenced in the materialized view.
Specify with ROWID and INCLUDING NEW VALUES.
Specify the SEQUENCE clause if the table is expected to have a mix of inserts/direct-loads, deletes, and updates.
Only SUM, COUNT, AVG, STDDEV, VARIANCE, MIN and MAX are supported for fast refresh.
COUNT(*) must be specified.
Aggregate functions must occur only as the outermost part of the expression. That is, aggregates such as AVG(AVG(x)) or AVG(x)+ AVG(x)
are not allowed.
For each aggregate such as AVG(expr), the corresponding COUNT(expr) must be present. Oracle recommends that SUM(expr) be
specified. See Requirements for Using Materialized Views with
Aggregates for further details.
If VARIANCE(expr) or STDDEV(expr) is specified, COUNT(expr) and SUM(expr) must be specified. Oracle recommends that SUM(expr *expr) be
specified. See Requirements for Using Materialized Views with
Aggregates for further details.
The SELECT column in the defining query cannot be a complex expression with columns from multiple base tables. A possible
workaround to this is to use a nested materialized view.
The SELECT list must contain all GROUP BY columns.
The materialized view is not based on one or more remote tables.
If you use a CHAR data type in the filter columns of a materialized view log, the character sets of the master site and the
materialized view must be the same.
If the materialized view has one of the following, then fast refresh is supported only on conventional DML inserts and direct
loads.
Materialized views with MIN or MAX aggregates
Materialized views which have SUM(expr) but no COUNT(expr)
Materialized views without COUNT(*)
Such a materialized view is called an insert-only materialized view.
A materialized view with MAX or MIN is fast refreshable after delete or mixed DML statements if it does not have a WHERE clause.
The max/min fast refresh after delete or mixed DML does not have the same behavior as the insert-only case. It deletes and recomputes
the max/min values for the affected groups. You need to be aware of
its performance impact.
Materialized views with named views or subqueries in the FROM clause can be fast refreshed provided the views can be completely
merged. For information on which views will merge, see Oracle Database
SQL Tuning Guide.
If there are no outer joins, you may have arbitrary selections and joins in the WHERE clause.
Materialized aggregate views with outer joins are fast refreshable after conventional DML and direct loads, provided only the
outer table has been modified. Also, unique constraints must exist on
the join columns of the inner join table. If there are outer joins,
all the joins must be connected by ANDs and must use the equality (=)
operator.
For materialized views with CUBE, ROLLUP, grouping sets, or concatenation of them, the following restrictions apply:
The SELECT list should contain grouping distinguisher that can either be a GROUPING_ID function on all GROUP BY expressions or
GROUPING functions one for each GROUP BY expression. For example, if
the GROUP BY clause of the materialized view is "GROUP BY CUBE(a, b)",
then the SELECT list should contain either "GROUPING_ID(a, b)" or
"GROUPING(a) AND GROUPING(b)" for the materialized view to be fast
refreshable.
GROUP BY should not result in any duplicate groupings. For example, "GROUP BY a, ROLLUP(a, b)" is not fast refreshable because it
results in duplicate groupings "(a), (a, b), AND (a)".
I think you missed
COUNT(*) must be specified.
For each aggregate such as AVG(expr), the corresponding COUNT(expr) must be present.
Specify with ROWID and INCLUDING NEW VALUES.
Specify the SEQUENCE clause if the table is expected to have a mix of inserts/direct-loads, deletes, and updates.
Is it possible to do updates via Resultset to an Oracle view? Asking as my code is giving me insufficient priviledge error when it does the rs.updateRow() call. I have checked and I definitely have access to the table/view.
The code looks like:
white (rs.next()) {
int updateStatus = getPSCforAction(status);
rs.updateInt("SPSC", updateStatus);
rs.updateRow;
}
The SELECT statement changes depends on operation but it will always be querying an Oracle view (and in some cases multiple views). My main question is whether updating via resultSet can be done to an Oracle view (or views)?
To answer your question one must see a definition of you view and a SELECT statament that is used to produce the resulset in your Java code. Without looking at this it is hard to give the answer
Anyway, generar rules and limitations are described in the Oracle Database JDBC Developer's guide:
Result Set Limitations
The following limitations are placed on queries for enhanced result
sets. Failure to follow these guidelines results in the JDBC driver
choosing an alternative result set type or concurrency type.
To produce an updatable result set:
A query can select from only a single table and cannot contain any
join operations.
In addition, for inserts to be feasible, the query must select all
non-nullable columns and all columns that do not have a default value.
A query cannot use SELECT * . However, there is a workaround for this.
A query must select table columns only.
It cannot select derived columns or aggregates, such as the SUM or MAX
of a set of columns.
To produce a scroll-sensitive result set:
A query cannot use SELECT *. However, there is a workaround for this.
A query can select from only a single table.
Scrollable and updatable result sets cannot have any column as Stream.
When the server has to fetch a Stream column, it reduces the fetch
size to one and blocks all columns following the Stream column until
the Stream column is read. As a result, columns cannot be fetched in
bulk and scrolled through.
They vaguely write that:
A query can select from only a single table and cannot contain any
join operations.
Could be that they mean "exlusively from tables, but not views", but also they could mean: "from tables and views", nobody knows, one must test this.
Another possible problem - your view may not be updatable, that is it doesn't conform to the following rules:
Notes on Updatable Views The following notes apply to updatable views:
An updatable view is one you can use to insert, update, or delete base
table rows. You can create a view to be inherently updatable, or you
can create an INSTEAD OF trigger on any view to make it updatable.
To learn whether and in what ways the columns of an inherently
updatable view can be modified, query the USER_UPDATABLE_COLUMNS data
dictionary view. The information displayed by this view is meaningful
only for inherently updatable views. For a view to be inherently
updatable, the following conditions must be met:
Each column in the view must map to a column of a single table. For
example, if a view column maps to the output of a TABLE clause (an
unnested collection), then the view is not inherently updatable.
The view must not contain any of the following constructs:
A set operator
A DISTINCT operator
An aggregate or analytic function
A GROUP BY, ORDER BY, MODEL, CONNECT BY, or START WITH clause
A collection expression in a SELECT list
A subquery in a SELECT list
A subquery designated WITH READ ONLY Joins, with some exceptions, as
documented in Oracle Database Administrator's Guide
In addition, if an
inherently updatable view contains pseudocolumns or expressions, then
you cannot update base table rows with an UPDATE statement that refers
to any of these pseudocolumns or expressions.
If you want a join view to be updatable, then all of the following
conditions must be true:
The DML statement must affect only one table underlying the join.
For an INSERT statement, the view must not be created WITH CHECK
OPTION, and all columns into which values are inserted must come from
a key-preserved table. A key-preserved table is one for which every
primary key or unique key value in the base table is also unique in
the join view.
For an UPDATE statement, the view must not be created WITH CHECK
OPTION, and all columns updated must be extracted from a key-preserved
table.
For a DELETE statement, if the join results in more than one
key-preserved table, then Oracle Database deletes from the first table
named in the FROM clause, whether or not the view was created WITH
CHECK OPTION.
I have a dimensional model with a large fact table (millions of rows) which is range partitioned by date and smaller dimensional tables that are not partitioned. I came across materialized views which is often used in these scenarios to improve query performance.
Now, I want to know which way is better of the following two to utilize these materialized views to get aggregated reports.
A. Create one with the by joining the whole fact table with each of the dimension tables required.
create materialized view my_mview execute immediate query rewrite
select
fact.col1, dim1.col2, dim2.col3, sum(fact.col4)
from
my_fact fact
inner join
my_dim1 dim1
on fact.dim1_key = dim1.dim1_key
inner join
my_dim2 dim2
on fact.dim2_key = dim2.dim2_key group by fact.col1, dim1.col2, dim2.col3
This seems like the most basic way of using them. But it seems
rather limiting and I would require a new materialzed view for each
variation of the query I want to create.
B. Create it over the aggregation of the fact table and utilize the query rewrite when doing a dimensional join back.
create materialized view my_mview execute immediate query rewrite
select
col1, dim1.dim2_key, dim2.dim_key, sum(fact.col4)
from
my_fact fact
And do the join as above in case A, which will use this aggregated materialzed view for the join and not the whole fact table.
Can anyone tell me when I would use each case or the other?
Your first example works exactly as you described.
For the second example the query should be:
create materialized view my_mview execute immediate query rewrite
select
col1, fact.dim2_key, fact.dim_key, sum(fact.col4)
from
my_fact fact
group by
col1, fact.dim2_key, fact.dim_key
This will automatically speed up aggregates such as
select sum(fact.col4)
from fact
select fact.dim_key,sum(fact.col4)
from fact
group by fact.dim_key
select fact.dim2_key,sum(fact.col4)
from fact
group by fact.dim2_key
I don't think Oracle will rewrite your first type of query to this MV automatically because in the MV the join columns are already grouped by (They also should be grouped in your second example). It never happened for us. This however may also depend on if there are relationships defined between dim and fact table and the value of QUERY_REWRITE_INTEGRITY parameter, so there is still some room for testing here.
You may still get a performance gain by writing a query in a specific way
WITH preaggr as (
select
col1, fact.dim2_key, fact.dim_key, sum(fact.col4)
from
my_fact fact
group by
col1, fact.dim2_key, fact.dim_key
)
select
dim2.col1,
sum(preaggr.col4)
from
preaggr
join
dim2
on
preaggr.dim2_key = fact.dim2_key
group by
dim2.col1
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.