如果LOGMNR获取的SQL_REDO或SQL_UNDO的长度超过4000,则会导致Oracle自动合并拆分行记录。
一个简单的例子来描述这个问题:
SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA; DATABASE altered. SQL> SELECT GROUP# FROM V$LOG WHERE STATUS = 'CURRENT'; GROUP# ---------- 2 SQL> ALTER SYSTEM SWITCH LOGFILE; System altered. SQL> SELECT GROUP# FROM V$LOG WHERE STATUS = 'CURRENT'; GROUP# ---------- 3 SQL> CREATE TABLE T_LARGE_SQL (ID NUMBER, COL1 VARCHAR2(4000), COL2 VARCHAR2(4000), COL3 VARCHAR2(4000)); TABLE created. SQL> INSERT INTO T_LARGE_SQL VALUES (1, 'A', 'A', 'A'); 1 ROW created. SQL> INSERT INTO T_LARGE_SQL VALUES (2, LPAD('B', 4000, 'B'), LPAD('B', 4000, 'B'), LPAD('B', 4000, 'B')); 1 ROW created. SQL> COMMIT; Commit complete. SQL> SELECT MEMBER FROM V$LOGFILE WHERE GROUP# = 3; MEMBER ---------------------------------------------------------------------------------------- /oracle/oradata/orcl/redo03.log SQL> ALTER SYSTEM SWITCH LOGFILE; System altered. SQL> EXEC DBMS_LOGMNR.ADD_LOGFILE('/oracle/oradata/orcl/redo03.log', DBMS_LOGMNR.NEW) PL/SQL PROCEDURE successfully completed. SQL> EXEC DBMS_LOGMNR.START_LOGMNR(OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG) PL/SQL PROCEDURE successfully completed. SQL> CREATE TABLE T_BAK_LOGMNR AS SELECT * FROM V$LOGMNR_CONTENTS; TABLE created. SQL> COL SQL_REDO FORMAT A80 WRAP SQL> SELECT RS_ID, SSN, CSF, SQL_REDO FROM T_BAK_LOGMNR WHERE SEG_NAME = 'T_LARGE_SQL'; RS_ID SSN CSF -------------------------------- ---------- ---------- SQL_REDO -------------------------------------------------------------------------------- 0x000069.0000001a.005c 0 0 CREATE TABLE T_LARGE_SQL (ID NUMBER, COL1 VARCHAR2(4000), COL2 VARCHAR2(4000), C OL3 VARCHAR2(4000)); 0x000069.0000002a.0010 0 0 INSERT INTO "TEST"."T_LARGE_SQL"("ID","COL1","COL2","COL3") VALUES ('1','A','A', 'A'); 0x000069.0000002a.01dc 0 1 INSERT INTO "TEST"."T_LARGE_SQL"("ID","COL1","COL2","COL3") VALUES ('2','BBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB . . . BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 0x000069.0000002a.01dc 0 1 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB','BBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB . . . BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 0x000069.0000002a.01dc 0 1 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB','B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB . . . BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 0x000069.0000002a.01dc 0 0 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB' ); 6 ROWS selected. |
由于SQL_REDO和SQL_UNDO都是VARCHAR2(4000)类型的字段,当SQL本身很长导致长度超过4000时,必须通过多条记录来保存这一条语句。当发生这种情况时,除了SQL_REDO和SQL_UNDO外,V$LOGMNR_CONTENTS视图中通过RS_ID和SSN来唯一标识一条语句。而CSF则标识当前是否是语句的结束部分。
比较有意思的是,Oracle并没有给出一个顺序列来标识同一个语句的多个行记录之间的先后顺序。虽然默认情况下,这个顺序由Oracle自动保证,但是一旦用户在查询V$LOGMNR_CONTENTS视图时添加了排序字段,这时一个语句中的行记录顺序就可能无法保证,因此介于这种情况,对于查询V$LOGMNR_CONTENTS视图需要谨慎一些。