Skip to Main Content
  • Questions
  • XID differs for ROLLBACK TO SAVEPOINT redo logs in V$LOGMNR_CONTENTS

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Jane.

Asked: February 04, 2025 - 5:24 pm UTC

Last updated: March 10, 2025 - 7:07 am UTC

Version: Oracle Database 19c Enterprise Edition Release 19.0.0.0.0

Viewed 1000+ times

You Asked

Oracle Version: Docker Image container-registry.oracle.com/database/enterprise:19.19.0.0
Setup Script (to enable logminer)
SELECT log_mode FROM v$database;
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;
SELECT log_mode FROM v$database;


ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;
select supplemental_log_data_min, supplemental_log_data_pk from v$database;


I'm using logMiner to get the redo logs, while i notice this strange behavior:

- Client Side Queries:


SELECT CURRENT_SCN FROM V$DATABASE; -- 2554427
INSERT INTO t1 VALUES (1, 1);
SAVEPOINT s1;
INSERT INTO t1 VALUES (2, 2);
SELECT CURRENT_SCN FROM V$DATABASE; -- 2554481
INSERT INTO t1 VALUES (3, 3);
SELECT CURRENT_SCN FROM V$DATABASE; -- 2554528
ROLLBACK TO s1;
SELECT CURRENT_SCN FROM V$DATABASE; -- 2554565
COMMIT;
SELECT CURRENT_SCN FROM V$DATABASE; -- 2554583


- To query logMiner for all the redo logs in this transaction:

EXEC DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => '/opt/oracle/oradata/ORCLCDB/redo01.log', OPTIONS => DBMS_LOGMNR.NEW);
EXEC DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => '/opt/oracle/oradata/ORCLCDB/redo02.log', OPTIONS => DBMS_LOGMNR.ADDFILE);
EXEC DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => '/opt/oracle/oradata/ORCLCDB/redo03.log', OPTIONS => DBMS_LOGMNR.ADDFILE);
EXEC DBMS_LOGMNR.START_LOGMNR(STARTSCN => 2554427, ENDSCN => 2554565, OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);
SELECT SCN, XID, XIDUSN, XIDSLT, XIDSQN, SQL_REDO, ROLLBACK FROM V$LOGMNR_CONTENTS WHERE TABLE_NAME = 'T1';


This gives me:


       
SCN XID                    XIDUSN    XIDSLT    XIDSQN SQL_REDO                                                             ROLLBACK 
__________ ___________________ _________ _________ _________ _________________________________________________________________ ___________ 
   2554454 D4001F0014000000          212        31        20 insert into "MY_USER"."T1"("PK","V") values ('1','1');                      0 
   2554475 D4001F0014000000          212        31        20 insert into "MY_USER"."T1"("PK","V") values ('2','2');                      0 
   2554524 D4001F0014000000          212        31        20 insert into "MY_USER"."T1"("PK","V") values ('3','3');                      0 
   2554545 D4001F0014000000          212        31        20 delete from "MY_USER"."T1" where ROWID = 'AAASkaAAHAAAAFcAAC';              1 
   2554545 D4001F0014000000          212        31        20 delete from "MY_USER"."T1" where ROWID = 'AAASkaAAHAAAAFcAAB';              1 




- To query logMiner for only the ROLLBACK TO s1 stmt:

EXEC DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => '/opt/oracle/oradata/ORCLCDB/redo01.log', OPTIONS => DBMS_LOGMNR.NEW);
EXEC DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => '/opt/oracle/oradata/ORCLCDB/redo02.log', OPTIONS => DBMS_LOGMNR.ADDFILE);
EXEC DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => '/opt/oracle/oradata/ORCLCDB/redo03.log', OPTIONS => DBMS_LOGMNR.ADDFILE);
EXEC DBMS_LOGMNR.START_LOGMNR(STARTSCN => 2554528, ENDSCN => 2554565, OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);
SELECT SCN, XID, XIDUSN, XIDSLT, XIDSQN, SQL_REDO, ROLLBACK FROM V$LOGMNR_CONTENTS WHERE TABLE_NAME = 'T1';


This gives:

       SCN XID                    XIDUSN    XIDSLT        XIDSQN SQL_REDO                                                             ROLLBACK 
__________ ___________________ _________ _________ _____________ _________________________________________________________________ ___________ 
   2554545 D4001F00FFFFFFFF          212        31    4294967295 delete from "MY_USER"."T1" where ROWID = 'AAASkaAAHAAAAFcAAC';              1 
   2554545 D4001F00FFFFFFFF          212        31    4294967295 delete from "MY_USER"."T1" where ROWID = 'AAASkaAAHAAAAFcAAB';              1 




So we can see that the actual XID should be `D4001F0014000000`. But if I narrow the SCN window for logMiner for just the ROLLBACK TO SAVEPOINT stmts, the last 8 digits of the XID will be padded with `FFFFFFFF`.

I'm wondering
- why this would happen?
- Is it possible to group sql_redo with the composite key of `(XIDUSN, XIDSLT)`, which seems to be consistent regardless of the scn window selection? In other words, if I found redo logs that share the same (XIDUSN, XIDSLT), can i say that they belong to the same transaction?

and Connor said...

I don't know off hand, but if I had to offer a hypothesis.

For a transaction rollback, we would only need the undo segments and slot number. The wrap sequence is used when a slot is reused over time, but if I am doing a rollback, I know by definition that the seg/slot contains my undo information because there is no way that slot can be marked for reuse until I commit. For an active transaction, the seg/slot *must* be mine because no-one gets to overwrite it.

In terms of when your large scn range picks up the wrap sequence, I'd surmise that its just getting carried forward into the subsequent entries for the rollback.

(I stress - this is just hypothesis)

More to Explore

Multitenant

Need more information on Multitenant? Check out the Multitenant docs for the Oracle Database