Oracle LogMiner结果不一致



我正在开发一个基于LogMiner的解决方案来捕获更改,并且在尝试挖掘与CLOB或BLOB操作相关的重做事件时,我发现了一组不寻常的期望。

在我的用例中,我已经将记录插入到一个包含3个CLOB字段的表中,其中一个CLOB域的值很小,而另外两个CLOB场必须使用LOB_WRITE操作进行设置。

当我设置一个在事务提交之前开始并在事务提交之后结束的起始LogMiner SCN范围时,我会在V$LOGMNR_CONTENTS中得到完整的预期行,它们是:

0a00070084220000 37717288 START
0a00070084220000 37717288 INSERT
0a00070084220000 37717312 SEL_LOB_LOCATOR
0a00070084220000 37717312 LOB_WRITE (several of these as expected)
0a00070084220000 37717331 SEL_LOB_LOCATOR
0a00070084220000 37717331 LOB_WRITE (several of these as expected)
0a00070084220000 37717332 INSERT (sets the smaller clob data values)
0a00070084220000 37717334 COMMIT

当使用特定的开始/结束SCN范围启动挖掘会话时,会出现异常位。

例如,当我从37717239挖掘到37717289时,我希望LogMiner在表中同时提供STARTINSERT;然而仅存在CCD_ 4操作。

此外,当我从37717290挖掘到37717340时,我希望LogMiner提供所有的SEL_LOB_LOCATORLOB_WRITE以及随后的INSERTCOMMIT;而只有随后的CCD_ 9和CCD_。

我能从中得出的唯一断言是,当你拆分一个transaction时,LogMiner似乎遇到了麻烦,在这个transaction中,某些重做事件代表了与LOB操作相关的各种合成操作,因此,我能够真正始终重建一系列事件的唯一方法是从37717288开始挖掘,以迫使LogMiner事务在具体化内容视图中的行时可用。

为什么LogMiner会这样做?为什么在使用我上面介绍的SCN范围拆分事务时,它没有正确实现?

对于Logminer,任何单个命令都是原子命令。在这种情况下,它开始于37717288,结束于37717332。它不能拆分。如果你会询问任何分割它的范围,Logminer不会故意提取它(所以你不会得到单个命令的部分结果(。

这也适用于大型非LOB命令,如生成许多内部命令的DDL(例如更改表修改列默认值(

此外,请注意,从Logminer中获取LOB的值是不可靠的。只要玩弄价值观,你就会发现它是高度不一致的。(我有一些测试可以证明这一点,所以如果你感兴趣,我可以提供(。

测试如下:定义一个有2个lob的表,创建2行——第一行有一个lob,第二行有两个lob。

drop table sample1.clobs2;
create table sample1.clobs2 (id number not null, clob1 clob not null, clob2 clob);
--start
select current_scn from v$database;
insert into sample1.clobs2 (id, clob1) values (3, 'abc');
insert into sample1.clobs2 (id, clob1, clob2) values (4, 'abc', '2abc');
commit;
update sample1.clobs2 set clob1='def' where id=3;
update sample1.clobs2 set clob1='def', clob2='2def' where id=4;
commit;
update sample1.clobs2 set clob1=rpad('ghj',30000,'Z') where id=3;
update sample1.clobs2 set clob1=rpad('ghj',30000,'Z'), clob2=rpad('ghj',30000,'Z') where id=4;
commit;

--end
select current_scn from v$database;

启动日志矿工:

exec DBMS_LOGMNR.end_LOGMNR;
exec DBMS_LOGMNR.ADD_LOGFILE('put here any logfile(select MEMBER from v$logfile), logminer will do the rest');
begin DBMS_LOGMNR.START_LOGMNR(
STARTSCN => put here the scn from the above test,
ENDSCN   => put here the scn from the above test,
OPTIONS  =>  -- I leave all the possible parameters here just for you to play
--DBMS_LOGMNR.DICT_FROM_REDO_LOGS +
--DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + 
DBMS_LOGMNR.CONTINUOUS_MINE +
--DBMS_LOGMNR.COMMITTED_DATA_ONLY+
--DBMS_LOGMNR.DDL_DICT_TRACKING+ 
DBMS_LOGMNR.NO_ROWID_IN_STMT+
DBMS_LOGMNR.NO_SQL_DELIMITER 
);
end;
/      

检查结果:

select scn, (XIDUSN || '.' || XIDSLT || '.' || XIDSQN) AS transaction_id, operation, seg_name, ROW_ID, rollback, csf,SQL_REDO,  c.*
from v$logmnr_contents c
where 1=1 
(seg_name='OBJ# put here the object id of the table sample1.clobs2' or operation='COMMIT');

您将看到:

  1. 大lob与小lob的行为不同
  2. 如果只更新了一个lob,则无法理解它是哪一个(第一个还是第二个(

此外,这种行为会在不同的Oracle版本之间发生变化。

最新更新