文章目录
一.前情:二.LogMiner介绍:三.logminer解析前提:3.1 开启归档模式3.2 启用补充日志(1)补充日志分类1.1 最小补充日志:最基本的一种数据库级补充日志;1.2标识关键字段补充日志(2)启用补充日志操作(3)提交进行的更改:3.3 创建用户帐户3.4 提取日志挖掘字典(重做日志)3.5 挖掘数据四、清除归档日志五、代码层面抽取数据一.前情:
军工、医疗、 电力等多个领域需要进行数据同步,如oracle生产库数据实时同步到hive数仓中。针对这些场景,选择logminer作为解析日志工具,从归档日志中实时抽取增量数据。在解析归档的过程中遇到非常多的问题(如rac集群2线程归档后日志的实际路径与视图中的路径不一致、日志激增导致程序内存溢出等),把排查过程、问题解决方法、心得记录下来,也许有用。
CDC的异步方式是非入侵方式(noninvasive)的实现,对于变化数据的捕获就不需要数据库加trigger。在CDC中变化的数据被保存在一个变化表中,使用者通过订阅的方式生成一个视图并且通过视图查询到变化的数据。
二.LogMiner介绍:
Oracle LogMiner作为Oracle数据库组成部分,可分析出所有对于数据库的DML操作(INSERT、UPDATE、DELETE)语句以及DDL操作,另外可分析得到回滚SQL语句,适用于日志挖掘。详情可翻阅LogMiner的英文文档: Oracle Logminer
三.logminer解析前提:
3.1 开启归档模式
以具有 DBA 权限的用户身份登录数据库。
检查数据库日志记录模式:
select log_mode from v$database;
如返回 ARCHIVELOG,跳到下一步。
如返回 NOARCHIVELOG,继续执行:
关闭数据库:
shutdown immediate;
启动数据库:
startup mount;
配置启用归档并打开数据库:
alter database archivelog;alter database open;
3.2 启用补充日志
(1)补充日志分类
1.1 最小补充日志:最基本的一种数据库级补充日志;
开启最小补充日志:
alter database add supplemental log data ;
查询是否启用最小补充日志:
select supplemental_log_data_min min from v$database ;
关闭最小补充日志:
alter database drop supplemental log data ;
1.2标识关键字段补充日志
有四种类型:主键、唯一索引、外键、全体字段补充日志;标识关键字段补充日志必须建立在最小补充日志的基础上,当其被启用时,若最小补充日志尚未启用,则oracle会隐式开启最小补充日志,同样在没有关闭标识关键字段补充日志的时候,不能先关闭最小补充日志。
1.2.1.主键补充日志
主键补充日志的作用是在update命令的重做记录中添加被修改行的主键字段的旧值,这是无条件式的补充日志,所谓无条件即无论主键字段本身是否被update命令修改,其旧值都会被记录。
但是,不能保证每张表一定有主键。如果存在没有主键的表,则主键字段由长度最小的非空唯一索引字段代替。如果表结构中一个非空索引字段都没有,那么oracle将被修改行的所有字段(除了lob和long类型)的旧值都记录下来,这将导致重做记录的数据量暴涨,所以如果要启用主键补充日志,又为了维护lgwr和重做日志,每张表最好具有主键或至少一个非空唯一字段。
启用主键补充日志:
alter database add supplemental log data (primary key) columns ;
1.2.2.唯一索引补充日志
只有当唯一字段被update时,才会记录该字段被修改前的值,因为唯一键索引是能够建立在多个字段上的
alter database add supplemental log data (unique) columns ;
1.2.3.外键补充日志
外键补充日志和唯一索引补充日志一样同为有条件式的,只有当外键字段被update命令修改时,其修改前的旧值才会被记录
alter database add supplemental log data (foreign key) columns ;
1.2.4.全体字段补充日志
全体字段补充日志和主键补充日志一样为无条件式的,无论哪个字段被update命令修改,所有字段(除了lob,long类型)的旧值都将被记录,其效果相当于启用了主键补充日志的前提下既没有主键也没有非空唯一索引字段的情况,这样几乎所有的表数据都搬到了重做日志中,不但存在当前的,历史数据也没有丢下。对恢复操作来说比较好,但是对于lgwr和磁盘空间就不是太好,一般很少启用这样的日志
alter database add supplemental log data (all) columns;
(2)启用补充日志操作
验证是否为数据库启用补充日志:
SELECT supplemental_log_data_min, supplemental_log_data_pk, supplemental_log_data_all FROM v$database;
如果三列都返回 Yes 或 Implicit,则启用了主键补充日志和全体字段补充日志,直接进行下一步
如果前两列返回 Yes 或 Implicit,则启用了主键补充日志,若满足需求,可进行下一步。
如果没有满足条件,则根据选择执行下面命令:
启用主键补充日志的2种方式:
(1)以单个表为单位启用
先启用最小补充日志,再启用主键补充日志
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;ALTER TABLE <schema name>.<table name> ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY)COLUMNS;
(2)一次性对数据库所有表启用
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;
启用全体字段补充日志的2种方式:
(1)以单个表为单位启用
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;ALTER TABLE <schema name>.<table name> ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
(2)一次性对数据库所有表启用
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
(3)提交进行的更改:
ALTER SYSTEM SWITCH LOGFILE;
3.3 创建用户帐户
CREATE USER <user name> IDENTIFIED BY <password>;GRANT create session, alter session, execute_catalog_role, select any dictionary, select any transaction, select any table to <user name>;GRANT select on v_$logmnr_parameters to <user name>;GRANT select on v_$logmnr_logs to <user name>;GRANT select on v_$archived_log to <user name>;GRANT select on <db>.<table> TO <user name>;
注:把UserB的所有表的查询权限给UserA
select 'grant select on '||owner||'.'||object_name||' to UserA;'from dba_objectswhere owner in ('UserB')and object_type='TABLE';
3.4 提取日志挖掘字典(重做日志)
仅在非高峰时间提取字典,因为操作会消耗数据库资源
EXECUTE DBMS_LOGMNR_D.BUILD(OPTIONS=> DBMS_LOGMNR_D.STORE_IN_REDO_LOGS);
3.5 挖掘数据
设置当前会话的时间格式:
ALTER SESSION SET NLS_DATE_FORMAT ='DD-MM-YYYY HH24:MI:SS';
设置会话区间,调用过程进行数据挖掘:
Execute DBMS_LOGMNR.START_LOGMNR( STARTTIME => to_date('20-03- 21:30:00','DD-MM-YYYY HH24:MI:SS'), ENDTIME => to_date('20-03- 22:30:00','DD-MM-YYYY HH24:MI:SS'), OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG+ DBMS_LOGMNR.CONTINUOUS_MINE+ DBMS_LOGMNR.NO_SQL_DELIMITER);
查询操作类型为1,3,2,25的日志相关信息
SELECT SCN,OPERATION_CODE, TIMESTAMP, SQL_REDO, TABLE_NAME,ROLLBACK, ROW_ID FROM V$LOGMNR_CONTENTS WHERE SEG_OWNER='HR' AND TABLE_NAME IN ('EMPLOYEES','EMP') AND OPERATION_CODE IN (1,3,2,25);
结束数据挖掘:
Execute DBMS_LOGMNR.END_LOGMNR;
注意:
V$LOGMNR_CONTENTS视图说明
四、清除归档日志
查看归档日志占用的空间:
select * from v$flash_recovery_area_usage;
查看归档日志的存放地址;
方法一:增大归档日志空间的大小
可以通过下面的方法来调整系统的回闪恢复区大小:
首先是关闭数据库:以SYS身份链接到oracle,执行>shutdown immediate;
启动数据库到mount状态:>startup mount
查看回闪恢复区的大小和存放目标:>show parameter db_recovery_file_dest
修改回闪恢复区的大小>alter system set db_recovery_file_dest_size = 8G
(缺省是2G,可以根据实际情况调整大小)
最后打开数据库:>alter database open;
方法二: rman删除
rman target sys/*****@orcl
DELETE ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-7';
(指定删除7天前的归档日志)
五、代码层面抽取数据
初始化 sql表达式
改变当前会话的格式:
ALTER SESSION SET NLS_DATE_FORMAT =‘DD-MM-YYYY HH24:MI:SS’;
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = ‘YYYY-MM-DD HH24:MI:SS.FF’;
ALTER SESSION SET NLS_NUMERIC_CHARACTERS = ‘.,’;
ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = ‘YYYY-MM-DD HH24:MI:SS.FF TZH:TZM’;
获取当前的scn
SELECT CURRENT_SCN FROM GV$DATABASE;
根据选择的方式,获取cdc初始处理的位置
选择的为LATEST,即获取当前时间为 配置中的startDate
实际上LATEST模式的处理为DATE的一种特殊模式,实际上仍然是按照DATE模式处理
判断数据库的版本以及处理的schema和表
数据库版本:
SELECT version FROM product_component_version;
schema和表
校验schema和表:
当版本大于等于11时,
初始化LogMnr表达式,
预编译:
selectFromLogMnrContents:
SELECT SCN, USERNAME, OPERATION_CODE, TIMESTAMP, SQL_REDO, TABLE_NAME, COMMIT_SCN, SEQUENCE#, CSF, XIDUSN, XIDSLT, XIDSQN, RS_ID, SSN, SEG_OWNER, ROLLBACK, ROW_ID FROM V$LOGMNR_CONTENTS WHERE ((( (SEG_OWNER=‘HR’ AND (TABLE_NAME IN ('EMPLOYEES
'))) ) AND (OPERATION_CODE IN (1,3,2,25))) OR (OPERATION_CODE = 7 OR OPERATION_CODE = 36))
存储过程:
startLogMnrForCommitSCN:
BEGIN DBMS_LOGMNR.START_LOGMNR( STARTSCN => ?, ENDSCN => ?, OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.CONTINUOUS_MINE + DBMS_LOGMNR.NO_SQL_DELIMITER); END;
startLogMnrForData:
BEGIN DBMS_LOGMNR.START_LOGMNR( STARTTIME => ?, ENDTIME => ?, OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.CONTINUOUS_MINE + DBMS_LOGMNR.NO_SQL_DELIMITER); END;
startLogMnrSCNToDate:
BEGIN DBMS_LOGMNR.START_LOGMNR( STARTSCN => ?, ENDTIME => ?, OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.CONTINUOUS_MINE + DBMS_LOGMNR.NO_SQL_DELIMITER); END;
endLogMnr:
BEGIN DBMS_LOGMNR.END_LOGMNR; END;
getTimestampsFromLogMnrContents:
SELECT TIMESTAMP FROM V$LOGMNR_CONTENTS ORDER BY TIMESTAMP
若使用重做日志(数据库的表结构发生变化时启用):
若存储在磁盘
存储在内存中,若解析sql,则需要创建固定线程数的线程池;若不解析sql,则创建单个工作线程的线程池,调用存储过程,获取归档日志数据
向线程池中提交runnable,把record提交导batchMaker
Oracle 补充日志分类和相关操作 logminer cdc实时同步数据变化 提取归档日志进行数据挖掘 相关代码实现