在过去的几个小时里,我读了很多关于在Oracle中刷新MV的文章,但是我仍然找不到答案。假设我在表的顶部有一个MV视图,上面有更改日志。所以在这个MV中有三个记录:
COL_ID, COL1
1, "OLD"
2, "OLD"
3, "OLD"现在,假设COL1的值已更改为用于创建MV的表中记录1的“编辑”。我想执行 fast ,就地刷新,以尽可能快地更新MV。在现实生活中有大约50M记录的例子中,刷新大约需要3分钟。
想象一下情况。
作为结果,将记录值为"OLD“或"EDITED”的?。
我理解,因为这是在通过刷新机制处理此记录之后的就地刷新,因此物化视图中的值将反映源表中的值(“已编辑”)。但是,是否有任何机制(如撤销日志)会使整个刷新成为原子的?我的意思是,除非对物化视图进行了所有修改(除非完成了刷新过程),否则如果用户查询正在进行刷新过程中修改过的行,那么他/她将被显示为一个旧的缓存值--在更改之前。
我猜想,这种现象对于异地更新是正确的,但由于前者在时间消耗方面似乎更有效率,所以我很好奇,对于就地转换是否也是如此。如果默认情况下不是,是否有任何方法强制这种原子行为?
-编辑
我在随后的测试中运行测试,看看在刷新过程中,从物化视图获得的结果是否会逐渐改变。
-- create table
create table MV_REFRESH_ATOMICITY_TEST
(
id NUMBER,
value NUMBER
)
-- populate initial data
-- delete from MV_REFRESH_ATOMICITY_TEST
declare
begin
for i in 1..10000000 loop
insert into MV_REFRESH_ATOMICITY_TEST values(i, 0);
end loop;
end;
-- check if equal zero and 1M
select sum(value) from MV_REFRESH_ATOMICITY_TEST
select to_char(count(*),'999,999,999') as COUNT from MV_REFRESH_ATOMICITY_TEST
-- create mv logs on the table
-- drop materialized view log on MV_REFRESH_ATOMICITY_TEST;
create materialized view log on MV_REFRESH_ATOMICITY_TEST with rowid;
-- create mv on top
-- drop materialized view MV_REFRESH_ATOMICITY_TEST_MV
create materialized view MV_REFRESH_ATOMICITY_TEST_MV
refresh fast on demand with rowid
as
select
fact.*,
fact.ROWID "FACT_ROWID"
from
MV_REFRESH_ATOMICITY_TEST fact
-- check if equals zero and 10M
select sum(value) from MV_REFRESH_ATOMICITY_TEST_MV
select to_char(count(*),'999,999,999') as COUNT from MV_REFRESH_ATOMICITY_TEST_MV
-- change value for first million records, 1 milion records in the middle, last milion of records
update MV_REFRESH_ATOMICITY_TEST set value = 1 where id between 1 and 1000000
update MV_REFRESH_ATOMICITY_TEST set value = 1 where id between 5000001 and 6000000
update MV_REFRESH_ATOMICITY_TEST set value = 1 where id between 9000001 and 10000000
-- check if equals 3.000.000
select to_char(sum(value),'999,999,999') as "SUM" from MV_REFRESH_ATOMICITY_TEST
-- check if equals 3.000.000
select to_char(count(*),'999,999,999') from MLOG$_MV_REFRESH_ATOMICITY;
--select * from MLOG$_MV_REFRESH_ATOMICITY;
-- while refreshing mv
-- exec dbms_mview.refresh('MV_REFRESH_ATOMICITY_TEST_MV', 'F');
-- below sum should be equal 0
select
( select sum(value) from MV_REFRESH_ATOMICITY_TEST_MV ) "SUM",
( select count(*) from MV_REFRESH_ATOMICITY_TEST_MV ) "NUMBER OF RECORDS"
from dual所以,我通过不断地执行最后一条select语句发现,只有求和值改变的时候,它已经改变了3M,这意味着所有的记录都在一次原子上被改变了。
尽管如此,并不能百分之百地肯定我可以相信这个实验,因为在某个时候,执行这些select查询需要大约40多岁。整个刷新语句花费了911 s来执行.
编辑
此问题已被标记为可能与this thread重复。另一个线程确实响应了类似的问题,但是对于一个complete-refresh (据我理解),它的执行方式与fast-refresh (这里的情况)非常不同。因此,我不知道是否可以在这里适用同样的解释。
发布于 2015-04-22 06:00:27
据我所知,从Oracle (01/server.102/b14226/repmview.htm#i31171)中可以看出,所有刷新都是以原子方式完成的:
物化视图的数据在任何时候都不一定与其主表或主物化视图的当前数据匹配。物化视图是作为数据存在于特定时间点(即在创建或刷新发生时)的主视图的事务(读)一致的反射。
Oracle提供了更好的与物化视图组的读取一致性:
为了保持多个物化视图之间的引用完整性和事务性(读)一致性,Oracle能够作为刷新组的一部分刷新单个物化视图。刷新组中的所有物化视图后,组中所有物化视图的数据对应于同一事务上一致的时间点。
https://stackoverflow.com/questions/29512791
复制相似问题