近期在研究OGG复制时,对于官方稳定中提到了11.2.0.4及以后的数据库出现了一种新的捕获日志的方法:integrated capture mode。该方法使用Log Mining Server捕获日志。故对于LogMiner进行了一些回顾,整理资料如下。
LogMiner用于分析重做日志和归档日志所记载的事务操作。 Logminer是oracle提供的用于分析重做日志信息的工具,它包括DBMS_LOGMNR和DBMS_LOGMNR_D两个package,后边的D是字典的意思。它既能分析redo log file,也能分析archive log file。分析日志需要使用数据字典,一般先生成数据字典文件再分析日志,10g以后的版本还可以使用在线数据字典。
1. 确定数据库误操作时间点或SCN。 假定某个用户执行drop table操作误删除了一张重要的表,通过LogMiner可以准确定位该误操作执行的时间或者SCN,然后通过基于时间或者SCN的恢复可以完全恢复该表数据。 2. 确定单个事务恢复操作。 假定某个用户在某表上执行了DML操作并提交了事务,并且该DML操作存在错误,则可以通过LogMiner可以取得任何用户的DML操作及其相应的UNDO操作,执行该UNDO操作可以取消该事务操作。 3. 执行后续审计。 通过LogMiner可以跟踪Oracle数据库的所有DML、DDL、DCL操作,从而取得执行这些操作的时间顺序、执行这些操作的用户等信息。
LogMiner可以使用产生redo log或archive log的数据库做分析(源数据库),也可以使用其他数据库做分析(分析数据库),为了将数据库内部对象ID号和数据类型转换为对象名和外部数据格式,需要使用LogMiner数据字典,否则无法读懂分析结果。
Redo log用户instance recovery和media recovery,这些操作所需要的数据都被自动记录在redo log中(一般记录rowid和修改的列值就足够了),但是如果想让解析出来的日志应用在其他方面,比如逻辑复制,则redo中还需要记录行中其他列的信息,以定位具体操作的行(因为源端和目标端rowid很可能是不一样的,不能用rowid来定位具体操作的行),记录其他列的日志被称为补充日志。
默认情况下Oracle数据库没有开启补充日志,从而导致LogMiner无法支持以下特性: IOT表,行链接,行迁移。 直接路径插入。 获取数据字段到重做日志。 跟踪DDL。 生成键列的SQL_REDO和SQL_UNDO信息。 LONG和LOB数据类型。
为了充分利用LogMiner,必须激活补充日志,此操作数据库不需要重启。
SQL> alter database add supplemental log data;三种使用方式: 1. 使用源数据库的数据字典(online catalog) 如果被分析的表的结构没有发生变化,建议使用该选项分析重做日志和归档日志。 该选项只能用于跟踪DML操作,不能用于跟踪DDL操作。(一般用来查询DML操作) 使用当前数据库的数据字典,需要在启动LogMiner时执行如下操作:
SQL> execute dbms_logmnr.start_logmnr (options=>dbms_logmnr.dict_from_online_catalog);2.摘取LogMiner字典到重做日志 如果被分析的表结构发生了变化 ,建议使用该选项分析重做日志和归档日志。也可用于使用分析数据库分析重做日志和归档日志。 操作如下:
SQL> execute dbms_logmnr_d.build(options=>dbms_logmnr_d.store_in_redo_logs);3.摘取LogMiner数据字典到操作系统文件 数据字典文件用于存放对象ID号和对象名的映射信息,该选项是为了与早期版本兼容而保留的(意思就是现在基本不用了)。 如果要分析新建的对象,必须重新建立字典文件。 操作如下:
SQL> execute dbms_logmnr_d.build ('logminer_dict.ora','/u01/app/oracle/arch',dbms_logmnr_d.store_in_flat_file);(可以用这种方式来查DDL的操作记录,如数据库没有配置utl_file_dir参数,需要配置后需要重启数据库)
从以下输出结果可以看出,oracle在插入sequence时是直接插入序列的值,这样在使用OGG进行逻辑复制的时候,即使主备两端sequence的nextval不相同也不影响数据正确插入,所以OGG中只要target端的sequence的nextval不小于source端的nextval即可。 对于LOB对象,是分段插入的。
SQL> select username,scn,timestamp,sql_redo from v$logmnr_contents where seg_name='LOGMINER_TABLE' and rownum <=12; USERNAME SCN TIMESTAMP ------------------------------ ---------- --------- SQL_REDO ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ LILI 926539 31-AUG-17 create table logminer_table ( id number(10) primary key, seq_test int, in_lob clob , out_lob clob ) lob (in_lob) store as (enable storage in row) lob (out_lob) store as (disable storage in row); LILI 926711 31-AUG-17 insert into "LILI"."LOGMINER_TABLE"("ID","SEQ_TEST","IN_LOB","OUT_LOB") values ('1','67',EMPTY_CLOB(),EMPTY_CLOB()); LILI 926711 31-AUG-17 DECLARE loc_c CLOB; buf_c VARCHAR2(6156); loc_b BLOB; buf_b RAW(6156); loc_nc NCLOB; buf_nc NVARCHAR2(6156); BEGIN select "IN_LOB" into loc_c from "LILI"."LOGMINER_TABLE" where "ID" = '1' and "SEQ_TEST" = '67' for update; LILI 926711 31-AUG-17 LILI 926712 31-AUG-17 buf_c := 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'; dbms_lob.write(loc_c, 1024, 1, buf_c); END; LILI 926712 31-AUG-17 buf_c := 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'; dbms_lob.write(loc_c, 1024, 1025, buf_c); END; LILI 926712 31-AUG-17 buf_c := 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'; dbms_lob.write(loc_c, 1024, 2049, buf_c); END; LILI 926712 31-AUG-17 buf_c := 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba'; dbms_lob.write(loc_c, 928, 3073, buf_c); END; LILI 926712 31-AUG-17 LILI 926712 31-AUG-17 LILI 926712 31-AUG-17 DECLARE loc_c CLOB; buf_c VARCHAR2(6156); loc_b BLOB; buf_b RAW(6156); loc_nc NCLOB; buf_nc NVARCHAR2(6156); BEGIN select "OUT_LOB" into loc_c from "LILI"."LOGMINER_TABLE" where "ID" = '1' and "SEQ_TEST" = '67' for update; LILI 926712 31-AUG-17 12 rows selected.简单命令操作如下:
--可以设置utl_file_dir参数,将生成的数据字典放在该目录下,设置该参数需要重启数据库 SQL> alter system set utl_file_dir='/home/oracle' scope=spfile; SQL> shutdown immediate SQL> startup SQL> execute dbms_logmnr_d.build ('lgmr_dict.ora','/home/oracle',dbms_logmnr_d.store_in_flat_file); SQL> execute dbms_logmnr.add_logfile(logfilename=>'/u01/app/oracle/arch/1_79_952761439.dbf',options=>dbms_logmnr.new); SQL> execute dbms_logmnr.start_logmnr(dictfilename=>'/home/oracle/lgmr_dict.ora',options=>dbms_logmnr.ddl_dict_tracking); SQL> select username,scn,timestamp,sql_redo from v$logmnr_contents SQL> execute dbms_logmnr.end_logmnr; --也可以不用改参数,直接在命令中指定要存放的路径 SQL> EXECUTE dbms_logmnr_d.build(dictionary_filename => 'lgmr_dict.ora',dictionary_location => '/home/oracle'); SQL> execute dbms_logmnr.start_logmnr(dictfilename=>'/home/oracle/lgmr_dict.ora');