1

我正在开发基于 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 同时提供表中的 theSTART和 the INSERT;但是只有START操作存在。

此外,当我从 37717290 挖掘到 37717340 时,我希望 LogMiner 提供所有的SEL_LOB_LOCATOR,LOB_WRITE和后续INSERT以及COMMIT; 然而,只有随后的INSERTCOMMIT在场。

我可以从中做出的唯一断言是,当您拆分事务时,LogMiner 似乎遇到了麻烦,其中某些重做事件表示各种合成操作,因为它们与 LOB 操作相关,因此我能够真正始终重建系列的唯一方法事件已从 37717288 向前挖掘,以强制 LogMiner 在实现内容视图中的行时拥有可用事务的全部范围。

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

4

1 回答 1

0

对于 Logminer,任何单个命令根据定义都是原子的。在这种情况下,它从 37717288 开始,到 37717332 结束。它不能被拆分。如果您要询问任何拆分它的范围 - Logminer 不会故意获取它(因此您不会有单个命令的部分结果)。

这也适用于大型非 LOB 命令,例如生成许多内部命令的 DDL(例如,alter table modify column default value)

除此之外,请注意从 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 版本之间发生变化。

于 2021-06-23T13:43:27.823 回答