#oracle #oracle19c #logminer
Вопрос:
Я работаю над решением на основе логмайнера для фиксации изменений, и я обнаружил, что кажется необычным набором ожиданий при попытке создать события повтора, относящиеся к операциям CLOB или BLOB.
В моем случае использования я вставил запись в таблицу, содержащую 3 поля CLOB, где значение одного из полей CLOB невелико, в то время как два других поля CLOB должны быть установлены с помощью операций LOB_WRITE.
Когда я устанавливаю начальный диапазон SCN LogMiner, который начинается до и заканчивается после фиксации транзакции , я получаю полные ожидаемые строки 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 предоставит и START
то, и INSERT
другое в таблице; однако присутствовала только START
операция.
Кроме того, когда я добывал с 37717290 по 37717340, я ожидал, что LogMiner предоставит все SEL_LOB_LOCATOR
, LOB_WRITE
, и последующие INSERT
и COMMIT
; однако присутствовали только последующие INSERT
и. COMMIT
Единственное утверждение, которое я могу сделать из этого, состоит в том, что у LogMiner, похоже, возникают проблемы при разделении транскрипции, в которой определенные события повтора представляют различные синтетические операции, связанные с операциями LOB, и, следовательно, единственный способ, которым я всегда мог реконструировать серию событий, был мой с 37717288 вперед, чтобы заставить LogMiner иметь полный объем транзакции, доступной, когда она материализует строки в представлении содержимого.
Почему LogMiner ведет себя так? Почему это неправильно материализуется при разделении транзакции с диапазонами SCN, которые я представил выше?
Ответ №1:
Для Logminer любая отдельная команда является атомарной по определению. В этом случае он начинается с 37717288 и заканчивается на 37717332. Его нельзя разделить. Если вы зададите какой — либо диапазон, который его разделяет, Logminer не будет извлекать его специально (поэтому у вас не будет частичных результатов одной команды).
Это также подходит для больших команд, не связанных с LOB, таких как DDL, которые генерируют множество внутренних команд (например, изменить таблицу, изменить значение столбца по умолчанию).
Кроме того, обратите внимание, что извлечение значений LOB из Logminer ненадежно. просто поиграйте со значениями, и вы увидите, что это очень противоречиво. (У меня где-то есть тесты, чтобы доказать это, так что, если вам интересно, я могу их предоставить).
Вот тест: определите таблицу с 2 вложениями, создайте 2 строки — первую с одним вложением и вторую с двумя вложениями.
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');
Вы увидите:
- большие потоки ведут себя иначе, чем маленькие
- в случае, когда обновляется только один lob — невозможно понять, какой это был (первый или второй)
Кроме того, это поведение меняется в разных версиях Oracle.
Комментарии:
1. Привет @Michael спасибо за этот информативный ответ. Я бы определенно хотел увидеть эти тесты, если это возможно, поскольку, возможно, стоит выразить мнение, что в конечном итоге это исследование для нас просто спорно. Мы не замечали никаких проблем с разделением транзакций при работе с базовыми операторами DML с использованием основных типов столбцов, пока мы не изучили LOB. Повторное разделение, я надеялся, что если мы предоставим функции запуска SCN до и после транзакции, то LogMiner получит необходимые данные, если диапазон SCN запроса был слишком мал, но, похоже, этого тоже не происходит. Есть ли какой-нибудь обходной путь?
2. Я взгляну на ваши тесты, но в нашем наборе есть несколько тестов, в которых мы выполняем обновления сразу для нескольких полей LOB, и мы можем решить, что есть что, проанализировав фрагменты SQL, которые являются частью операции SEL_LOB_LOCATOR, кстати.
3. @Naros — Что касается ваших вопросов о диапазонах SCN: когда включена функция COMMITTED_DATA_ONLY, «фиксация» должна быть в диапазоне.
4. Правильно, но, по крайней мере, на данный момент мы не используем эту опцию, мы обнаружили, что эта опция была столь же болезненной, поскольку вам также потребуется запустить scn в диапазоне, чтобы получить полную картину транзакции, когда она совершится.