【发布时间】:2015-06-13 07:14:02
【问题描述】:
在过去的几个小时里,我已经阅读了很多关于在 Oracle 中刷新 MV 的内容,但我仍然找不到我的问题的答案。想象一下,我在带有更改日志的表顶部有一个 MV 视图。所以这个MV里有3条记录:
COL_ID, COL1
1, "OLD"
2, "OLD"
3, "OLD"
现在假设用于创建 MV 的表中记录 1 的 COL1 的值已更改为“EDITED”。我想执行 fast、in-place 刷新以尽快更新 MV。在具有大约 50M 条记录的实际示例中,刷新大约需要 3 分钟。
想象一下情况。
- 刷新过程仍在运行(MV中仍有未修改的记录)。
- 无论如何,ID = 1 的记录已被处理,因此它在 MV 中的值为“EDITED”。
- 在另一个会话中,执行对 MV 的查询以获取 ID = 1 的记录的值。
结果会给出值为“OLD”或“EDITED”的记录?
我了解,因为这是在刷新机制处理此记录后的就地刷新,所以物化视图中的值将反映原始表中的值(“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 语句发现,唯一一次 SUM 值改变时,它已经改变了 3M,这意味着所有记录都被一次性改变了 - 原子。
尽管如此,我不能 100% 确定我可以相信这个实验,因为在某些时候执行这些选择查询需要大约 40 秒。整个刷新语句执行耗时 911 秒。
[编辑]
此问题已被标记为可能与 this thread 重复。另一个线程确实响应了类似的问题,但是对于 complete-refresh,据我了解,它的执行方式与 fast-refresh 非常不同,这里就是这种情况。因此,我不确定是否可以在这里应用相同的解释。
【问题讨论】:
标签: oracle atomic materialized-views