I'm trying to create a materialized view on prebuilt table with this syntax
CREATE MATERIALIZED VIEW "STORE"
ON PREBUILT TABLE
WITH REDUCED PRECISION
REFRESH FORCE ON DEMAND
START WITH SYSDATE+4/1440
NEXT SYSDATE + 1/24
USING DEFAULT LOCAL ROLLBACK SEGMENT
DISABLE QUERY REWRITE
AS
(
(SELECT
t1.field1
t1.field2
t1.field3
t3.LAT AS LAT,
t3.LNG AS LNG,
t4.ID AS T4_ID
FROM T1#STORE_DBLINK t1
INNER JOIN T4 t4 ON t1.T4_ID = t4.ID
LEFT JOIN T3#STORE_DBLINK t3 ON t3.STORE_NUMBER = t1.NUMBER
WHERE ((t1.id = (
SELECT MAX(t2.id)
FROM T2#STORE_DBLINK t2
WHERE t2.number=t1.number
))
))
UNION
(SELECT te.field1,
te.field2,
te.field3,
te.LAT LAT,
te.LNG LNG,
te.T4_ID
FROM STORE_TMP te
WHERE STORE_NUMBER not in (select DISTINCT NUMBER from T1S#STORE_DBLINK)));
This query creates the materialized view correctly. However, when I "Edit" the materialized view via SqlDeveloper the refresh period is disabled, and the rollback segment appears like "Unspecified".
Furthermore, if I try to change Refresh "On demand" to a time period with next refresh, it nevers complete the change. The same thing happens if I execute:
ALTER MATERIALIZED VIEW STORE
REFRESH FORCE
START WITH SYSDATE+4/1440
NEXT SYSDATE+1/24;
Maybe this is due to the fact that I'm using a complex materialized view? Is there a way to fix this?
Thanks in advance.
Related
I want to create m-view which keeps the aggregates of cash from transaction history.
The query is as follows.
CREATE MATERIALIZED VIEW MV_CASH_STATS
BUILD IMMEDIATE REFRESH FAST ON DEMAND
AS
( -- Total aggregates
SELECT
'total' AS CODE
, COUNT(T.CASH_IN) AS DEPOSITS
, COUNT(T.CASH_OUT) AS WITHDRAWS
, SUM(T.CASH_IN) AS DEPOSIT
, SUM(T.CASH_OUT) AS WITHDRAW
FROM
TB_CASH_LOG T
)
UNION ALL
( -- Aggregates by account grades
SELECT
'grade-' || T1.GRADE AS CODE
, COUNT(T.CASH_IN) AS DEPOSITS
, COUNT(T.CASH_OUT) AS WITHDRAWS
, SUM(T.CASH_IN) AS DEPOSIT
, SUM(T.CASH_OUT) AS WITHDRAW
FROM
TB_CASH_LOG T
INNER JOIN TB_ACCOUNT T1 ON
T.ACCOUNT_ID = T1.ID
GROUP BY T1.GRADE
)
When i execute this, the following error occurs.
> ORA-12015: cannot create a fast refresh materialized view from a complex query
(I created m-view log tables for both TB_CASH_LOG and TB_ACCOUNT)
The Total aggregates part is ok, but the later part - Aggregates by account grades - makes the error.
I've read Oracle basic materialized view docs, and thinking that INNER JOIN or GROUP BY is the error point.
If it is true, fast refresh m-view with inner join and group by is impossible?
What is wrong with my m-view declaration sql?
p.s. I'm working on oracle 18c
I created a materialized view as show below:
CREATE MATERIALIZED VIEW ORA2ORA_DW.INVOICE_AGG
BUILD IMMEDIATE
REFRESH FORCE
ON DEMAND
DISABLE QUERY REWRITE
AS
SELECT C.CUSTOMERID , C.CUSTOMERNAME, SUM(I.QUANTITY) AS QUANTITY, MAX(I.UNITPRICE) AS UNITPRICE, MIN(I.TAXAMOUNT) AS AMOUNT,
AVG(I.TAXRATE) AS TAX, VARIANCE(I.LINEPROFIT)AS LINEPROFIT_VAR, STDDEV(I.LINEPROFIT) AS LINEPROFIT_STDEV, COUNT(I.INVOICELINESKEY) AS ROW_COUNT
FROM ORA2ORA_DW.INVOICELINES I, ORA2ORA_DW.CUSTOMERS C
WHERE I.CUSTOMERSKEY=C.CUSTOMERSKEY
GROUP BY C.CUSTOMERID , C.CUSTOMERNAME
ORDER BY C.CUSTOMERID;
but when I try to refresh it using this command "EXEC DBMS_MVIEW.REFRESH('INVOICE_AGG');", it gives me this error: ORA-00900: invalid SQL statement
This is the query i am running:
select /*+ index(V_AMV_PLG_ORDER_HISTORY_200_MS.orders.T0 IDX_ORDER_VERSION_3) */ *
from V_AMV_PLG_ORDER_HISTORY_200_MS
where EXCHANGE_SK = 32 and PRODUCT_SK = 1000169
And it uses a different index than the one i am ordering it to.
As you can see, I am querying from the view V_AMV_PLG_ORDER_HISTORY_200_MS, you can see its sql query here:
V_AMV_PLG_ORDER_HISTORY_200_MS view SQL Query:
SELECT AMV_PERF_PROFILES_FRONTEND.AMV_PLG_GET_SEGMENT(200, orders.ORDER_GLOBAL_DATE_TIME) AS ORDER_DATE_TIME,
SUM(orders.BASE_VOLUME) AS VOLUME,
SUM(orders.BASE_CURR_LIMIT_PRICE*orders.BASE_VOLUME)/SUM(orders.BASE_VOLUME) AS PRICE,
orders.PRODUCT_SK AS PRODUCT_SK,
orders.EXCHANGE_SK AS EXCHANGE_SK,
orders.DIRECTION_CD AS DIRECTION_CD,
orders.AGG_UNIT_CD AS AGG_UNIT_CD,
orders.TRADER_KEY AS EXECUTING_REPRESENTATIVE_KEY,
orders.ACCOUNT_KEY AS ACCOUNT_KEY,
a.BUSINESS_UNIT_CD AS BUSINESS_UNIT_CD
FROM AMV_PERF_PROFILES_FRONTEND.S_AMV_ORDER_VERSION_NEW orders
INNER JOIN AMV_PERF_PROFILES_FRONTEND.S_AMV_ACCOUNT a
ON a.ACCOUNT_KEY = orders.ACCOUNT_KEY
WHERE BASE_VOLUME > 0
GROUP BY AMV_PERF_PROFILES_FRONTEND.AMV_PLG_GET_SEGMENT(200, orders.ORDER_GLOBAL_DATE_TIME),
orders.PRODUCT_SK,
orders.EXCHANGE_SK,
orders.ACCOUNT_KEY,
a.BUSINESS_UNIT_CD,
orders.AGG_UNIT_CD,
orders.TRADER_KEY,
orders.DIRECTION_CD;
He is getting the data using the Synonym S_AMV_ORDER_VERSION_NEW, Which directs to another Scheme, to a view called V_AMV_ORDER_VERSION and refering to it as orders, its sql query here:
V_AMV_ORDER_VERSION view Sql query:
SELECT T1.ENTITY_KEY ,
T2.AGG_UNIT_CD ,
T0.BASE_CURR_LIMIT_PRICE ,
T7.DIRECTION_CD ,
T0.EXCHANGE_SK,
T0.ORDER_LOCAL_DATE_TIME ,
T0.PRODUCT_SK,
T18.ENTITY_KEY ,
T19.ENTITY_KEY ,
T0.NOTIONAL_VALUE2 ,
T0.NOTIONAL_VALUE ,
T0.ORDER_GLOBAL_DATE_TIME ,
T0.BASE_VOLUME ,
T31.TRANSACTION_STATUS_CD ,
T0.ORDER_VERSION_KEY
FROM ETS_UDM_CDS_NEW.ORDER_VERSION T0
LEFT OUTER JOIN ETS_UDM_CDS_NEW.ENTITY T1
ON T0.ACCOUNT_SK = T1.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.AGG_UNIT T2
ON T0.AGG_UNIT_SK = T2.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.DIRECTION T7
ON T0.DIRECTION_SK = T7.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.ENTITY T18
ON T0.LOCAL_TIME_ZONE_SK = T18.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.ENTITY T19
ON T0.TRADER_SK = T19.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.TRANSACTION_STATUS T31
ON T0.TRANSACTION_STATUS_SK = T31.ENTITY_SK;
Which takes its data from a table called ORDER_VERSION and refers to it as T0
this table has an index called IDX_ORDER_VERSION
The problem is that oracle ignores my hint, And uses a different index, Now, I have managed to use a hint to make oracle use an index i wanted when i was querying a view that gets data from a table, But this time I am querying a view which gets his data from another view which gets his data from a table.
And also, The second view in the line is on a different Scheme and i am using a synonym, So perhaps that is why i am missing something Cuz i tried many combinations of possible solutions i found on google but nothing seems to be working...
I would say that if i go one step forward and query directly from V_AMV_ORDER_VERSION (Without the synonym) IT works and i can make oracle work with any index i want, so this query works perfect:
select /*+ index(orders.T0 IDX_ORDER_VERSION_5) */ * from V_AMV_ORDER_VERSION orders
where EXCHANGE_SK =32 and PRODUCT_SK = 1000169
Well me and our company's DBA looked at it for a while, it seems like an Oracle bug in the Global Hint manifestation, We have created the view V_AMV_PLG_ORDER_HISTORY_200_MS using a regular join rather than an ANSI join, and now it works properly:
V_AMV_PLG_ORDER_HISTORY_200_MS view SQL Query:
SELECT AMV_PERF_PROFILES_FRONTEND.AMV_PLG_GET_SEGMENT(200, orders.ORDER_GLOBAL_DATE_TIME) AS ORDER_DATE_TIME,
SUM(orders.BASE_VOLUME) AS VOLUME,
SUM(orders.BASE_CURR_LIMIT_PRICE*orders.BASE_VOLUME)/SUM(orders.BASE_VOLUME) AS PRICE,
orders.PRODUCT_SK AS PRODUCT_SK,
orders.EXCHANGE_SK AS EXCHANGE_SK,
orders.DIRECTION_CD AS DIRECTION_CD,
orders.AGG_UNIT_CD AS AGG_UNIT_CD,
orders.TRADER_KEY AS EXECUTING_REPRESENTATIVE_KEY,
orders.ACCOUNT_KEY AS ACCOUNT_KEY,
a.BUSINESS_UNIT_CD AS BUSINESS_UNIT_CD
FROM AMV_PERF_PROFILES_FRONTEND.S_AMV_ORDER_VERSION_NEW orders,
AMV_PERF_PROFILES_FRONTEND.S_AMV_ACCOUNT a
WHERE BASE_VOLUME > 0 AND a.ACCOUNT_KEY = orders.ACCOUNT_KEY
GROUP BY AMV_PERF_PROFILES_FRONTEND.AMV_PLG_GET_SEGMENT(200, orders.ORDER_GLOBAL_DATE_TIME),
orders.PRODUCT_SK,
orders.EXCHANGE_SK,
orders.ACCOUNT_KEY,
a.BUSINESS_UNIT_CD,
orders.AGG_UNIT_CD,
orders.TRADER_KEY,
orders.DIRECTION_CD;
I have two tables 'survey' & 'survey_processed' and both are basically similar tables. I have a working query which uses UNION ALL operator between two tables & am getting some counts. When I try to translate it in to a Materialized View, I get the error related to ON COMMIT. Check out the MV DDL & Error below.
CREATE MATERIALIZED VIEW vwm_survey_records_count
REFRESH FAST ON COMMIT
AS
SELECT
survey_combined.survey_header_id,
COUNT(*) AS count_total,
COUNT(CASE WHEN survey_combined.processed_flag = 'Y' THEN 1 ELSE NULL END) AS count_a,
COUNT(CASE WHEN survey_combined.approved_flag IS NULL THEN 1 ELSE NULL END) AS count_b,
COUNT(CASE WHEN survey_combined.processed_flag = 'N' AND survey_combined.approved_flag = 'Y' THEN 1 ELSE NULL END) AS count_c,
COUNT(CASE WHEN survey_combined.approved_flag = 'N' THEN 1 ELSE NULL END) AS count_d
FROM
(
SELECT survey_header_id, 'N' AS processed_flag, approved_flag FROM survey
UNION ALL
SELECT survey_header_id, 'Y' AS processed_flag, approved_flag FROM survey_processed) survey_combined
INNER JOIN survey_header ON survey_combined.survey_header_id = survey_header.id
GROUP BY survey_combined.survey_header_id;
Error I get if i run the above command:
'SQL Error: ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view' .
But, if i use the 'REFRESH COMPLETE ON DEMAND' it works. I know am obviously breaking some restrictions for the ON COMMIT attribute, but can't figure out which. Can someone let me know what am doing wrong on the above query? Also, Is there any better approach for the query as such to make it efficient & work with 'REFRESH FAST ON COMMIT', while creating the MV.
Note: I have the MV Log created for both the tables using rowid on the selected columns.
Let me know if someone has any questions.
Thanks in advance.
Here's the DDL for MV Log as requested by 'jonearles'
CREATE MATERIALIZED VIEW LOG ON survey WITH SEQUENCE,ROWID (id, survey_header_id, approved_flag, processed_flag) INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON survey_processed WITH SEQUENCE,ROWID (id, survey_header_id, approved_flag) INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON survey_header WITH SEQUENCE,ROWID (id) INCLUDING NEW VALUES;
Note: The column 'processed_flag' in the 'survey' table will be dropped later on. Technically, the two tables were recently split based on the value of the 'processed_flag' column. So, the 'survey' table has all the un-processed records (processed_flag = 'N') & 'survey_processed' has the processed records (processed_flag = 'Y'). After the split, the column is irrelevant.
I think you're out of luck here. From Restrictions on Fast Refresh on Materialized Views with UNION ALL:
The defining query must have the UNION ALL operator at the top level.
And replacing the UNION ALL with outer joins doesn't work either. Aggregation and outer joins don't appear to work together. The code below is not equivalent to yours, but it demonstrates that even a much simplified version of your query won't work:
CREATE MATERIALIZED VIEW vwm_survey_records_count
REFRESH COMPLETE ON DEMAND AS
SELECT survey_header.id AS survey_header_id, COUNT(*) AS count_total
FROM survey_header, survey, survey_processed
WHERE survey_header.id = survey.survey_header_id(+)
GROUP BY survey_header.id;
delete from MV_CAPABILITIES_TABLE;
begin
DBMS_MVIEW.EXPLAIN_MVIEW ('VWM_SURVEY_RECORDS_COUNT');
end;
/
select possible, msgno, msgtxt
from MV_CAPABILITIES_TABLE
where capability_name = 'REFRESH_FAST_AFTER_INSERT';
POSSIBLE MSGNO MSGTXT
-------- ----- ------
N 2048 outer join in mv
I have a query as follows
select *
from
( select id,sum(amt) amt from table_t group by id
) t inner join table_v v on (v.id = t.id)
order by t.amt desc;
table_t has no index and has 738,000 rows and table_v has an index on id and has 158,000 rows.
The query currently fetches the results in 10 seconds.
The explain query plan shows a full table scan.. How can I improve the performance here ?
If I add an index on id for table_t will it help. Because I am using it in a subquery ?
If you have an index on (id,amt) you would minimise the work in the group by/summation process (as it could read the index). If both columns are nullable then you may need to add a "where id is not null" so it will use the index. [That's implied by the later join on id, but may not get inferred by the optimizer.]
Next step would be to use a materialized view for the summation, maybe with an index on (amt,id) (which it could use to avoid the sort). But that is refreshed either at a commit or on request or at scheduled intervals. It doesn't help if you need to do this query as part of a transaction.
Both the index and the materialized view would add work to inserts/updates/deletes on the table but save work in this query.