We have a materialized view (MV) on Oracle 19c. Its data is updated/refreshed by scheduler job every day.
Because of some maintenance work that may last for more than 6 months, I would like to update some data inside it manually. However, manual update is forbidden on MV.
It may sound stupid but I am planning to:
Disable to the scheduler job
Turn the MV into table (DROP MATERIALIZED VIEW .. PRESERVE TABLE; )
Then we can update the table data manually for our maintenance work.
After the maintenance work, I would:
Turn the table back to MV
Re-enable the scheduler job to refresh the data
So the question is... how do I turn the table back to MV SAFELY in my case? It is easy to turn MV into table but I have never heard anyone doing it the other way round.
By safely, I mean that the reverted MV is back to before without lost of behaviours/properties.
If I turn the MV to table and then back to MV, would the index still work for both the table and the MV without affected?
Similarly, if we already have a synonym for the MV, would this synonym still work after converting to table and back to MV again?
Do I need re-grant any user privileges to the table and later for the MV again?
Note: I am aware that after turning the table back to MV, the data get refreshed and our manual data would be lost. That is acceptable for us because we just want the manual data to stay during the maintenance period.
If there are other suggestions/alternatives, I am happy to hear.
Combining synonym, patch table and views might be a good solution for temporary situation as suggested.
And then..
You can safely recreate materialized view with
CREATE MATERIALIZED VIEW testmv ON PREBUILT TABLE ...
Indexes can be used till refresh. You don't need to re-grant user privileges
Synonyms that crated previously for MV still works after creating MV from prebuilt table.
What is the reason to update some data inside the mview? Maybe you need a table, not a mview. Just refresh the materialized view to update the data, or change the related SQL to reflect the dataset you want. Other way it would be as inconsistent state.
Turn the table back to MV
If you understand that after that step, the MV is refreshed with the life data and your changes to the underlaying table are lost, it's OK.
Another way to do the job is to access the MV through a VIEW, and changes the definition of the VIEW for the maintenance work (conceptually "select from MV where not exists (select FROM PATCH) UNION ALL select from PATCH"), and putting it back to "select FROM MV" when done).
(And note that truncate PATCH will have the same effect, and you don't have to change the VIEW...)
Related
We have a table TB_1 which has monthly and weekly data partitioned by monthly and weekly columns. We also have materialized view MV_1 inherited from the table TB_1.
We would like to refresh the materialized view by certain weekly or monthly basis.
Not sure how we can filter out weekly or monthly changes from all the changes captured in the materialized log for partial refresh.
Right now we are thinking to have a flag column in TB_1. By clearing the materialized log and updating the flag, We think we can achieve this.
Is there anyway efficient way than the process for partial refresh on specific criteria?
We have a similar case here: the solution we found was to partition the materialized view month by month (using PCT ). If you have this as an option in your licensing, this could be a solution. Then you must partition the "details tables", TB_1, and probably the "details tables" of MV_1.
execute dbms_mview.refresh(
list => 'your_partitioned_mview'
, method => 'P' -- this is where PCT is specified
, atomic_refresh => false
);
There are also other solution on Is it possible to partially refresh a materialized view in Oracle? .
edit:
I'd say the solution of a fast refresh using a "to be refreshed" flag is worth being tried. Not sure you need to clear the Mview log beforehand. Just changing the value of the flag for the record to be updated should work. Here is a nice howto I found.
If you have Oracle 12.2, they introduced real-time Mviews, which might be what you are looking for...
Oracle 12.2 introduced the concept of real-time materialized views, which allow a statement-level wind-forward of a stale materialised view, making the data appear fresh to the statement. This wind-forward is based on changes computed using materialized view logs, similar to a conventional fast refresh, but the operation only affect the current statement. The changes are not persisted in the materialized view, so a conventional refresh is still required at some point.
#use416, please keep us posted for what actually worked for your case.
When inserting a row I want to set a column, equal to the current time on commit.
If I use default value sysdate on the column, it uses the current time at insert (which could be significantly different to commit time). If I use an on insert trigger, it again uses the time at the insert - not the actual commit.
Are there any possible solutions to get current time on commit with oracle ?
There are options. They may be rather more heavyweight than you were hoping for, though.
You could create a fast-refreshable materialized view that refreshes on commit and put a trigger on that materialized view that would fire when the row commits. That would mean, though, that you'd need a materialized view log on the base table so your insert would incur the overhead of writing to the table and the log plus you'd incur the cost of the materialized view refresh when you committed. If you ever had to do a full refresh of the materialized view, you'd need to make sure to turn off the trigger as well. That's quite a few moving pieces that will add complexity to your system.
Depending on the Oracle version, you might be able to enable Flashback Data Archive (also known as Total Recall) which would record the SCN and timestamp of when each version of data was committed. The downside there is that you'd then have a potentially large history table that is likely tracking a bunch of information that you don't care about.
I have a materialized view I would like to alter to on commit (from on demand) using fast refresh.
However I constantly get
ora-32337 cannot alter materialized view with pending changes refresh on commit
even directly after a refresh (and knowing that no change was done).
What could be the cause for this? The MV uses outer joins, could that be an issue? (MV log is available for all tables)
As #eaolson said you should just drop the materialized view and recreate it as refresh on commit. This the only way..
How can I update a materialized view? Is there any downside to updating materialized views? I'm in a situation where I can either
Update the materialized view (OR)
Copy the records to another table, update them, truncate or drop the materialized view table, insert the updated records back into the materialized view.
These two options revolve around the long amount of time required to rebuild the materialized view (literally 5+ days).
Version : Oracle 10g
The intention of a materialized view is to store the results of some complex long running query that the query rewrite mechanism can use to save lots of time. It looks like the sql that is used to build the MV needs some tweeking.
You cannot update an MV, unless you meant doing a full/fast refresh/rebuild.
What is eating the time in during the MV refresh? Did you check the addm reports?
Did you configure full or fast refreshes?
I have a very complex Oracle view based on other materialized views, regular views as well as some tables (I can't "fast refresh" it). Most of the time, existing records in this view are based on a date and are "stable", with new record sets having new dates.
Occasionally, I receive back-dates. I know what those are and how to deal with them if I were maintaining a table, but I would like to keep this a "view". A complete refresh would take around 30 minutes, but it only takes 25 seconds for any given date.
Can I specify that only a portion of a materialized view should be updated (i.e. the affected dates)?
Do I have to scrap the view and use a table and a procedure to populate or refresh a given date in that table?
Partition by date as in answer 3 (skaffman).
You could just do the refresh of a normal mv(table_refreshed below) and than use the exchange keyword i.e.
ALTER TABLE all_partitions
EXCHANGE PARTITION to_calculate
WITH TABLE table_refreshed
WITHOUT VALIDATION
UPDATE GLOBAL INDEXES;
After more reading and judging by the lack of answers to this question, I come come to the conclusion that it is not possible to refresh a single partition of a materialized view.
If you can give a syntax example that proves otherwise, I will happily mark your answer the accepted one.
To others who might find this questions useful in the future: you might also want to know that in Oracle 10g, refreshing a partition (or any mview) will cause Oracle to issue DELETE, followed by INSERT.
If this is giving you performance problems (like me), there is an option to use atomic_refresh => false, which will TRUNCATE, then INSERT /*+APPEND*/.
I have been able to refresh a single partition of a materialized view with partition change tracking.
It seems to require that the view is created with REFRESH FAST WITH ROWID option and DBMS_MVIEW.REFRESH is called with 'P' method.
You can partition materialized views just as you can with normal tables. Partition your mview by date, and then you can refresh only the required partition.