ParnassusData is a software company Oracle streams 参数优化实验报告 诗檀软件 www.parnassusdata.com 工程师 : 报告生成日期 : 更新日期 : 郭兆伟 2015 年 7 月 20 日 2015 年 7 月 20 日
文档控制 此文档仅供诗檀软件内部审阅, 不得向与此无关的个人或机构传 阅或复制 变更记录 日期作者及更新人版本号变更信息 审阅人 版本号审阅人职位相关评 1.0 论 审批人 版本号批准人日期相关评论 文档分发 分发号文档名分发位置 1 SHCH-1 ASANA 诗檀软件 Oracle 数据库健康检查报告 2
目录 文档控制 2 变更记录... 2 审阅人... 2 审批人... 2 文档分发... 2 目录... 3 1. 实验环境... 3 2. 实验及其结果... 3 2.1 模拟 update 冲突... 4 2.1.1 没有任何冲突解决程序... 4 2. 1.2 使用错误处理程序 :... 5 2.1.3 创建 update 的冲突解决程序... 6 2.1.4 模拟目标端找不到行记录的情况 ( 由于目标端 delete 或 update, 导致源端的 LCR 过来之后找不到行记录 )... 9 2.1.5 模拟违反唯一主键的情况 ( 由于目标端 insert 或者 update, 导致源端的 LCR 过来后违反约束的情况 )... 14 3. stream 健康检查... 16 4. 总结... 16 5. 其他问题... 17 5.1 未解决的问题... 17 已解决的问题... 17 1. 实验环境 虚拟机环境 rhel 5.6_64 oracle 10.2.0.4 之前搭建的一个双节点 streams 的环境, 关闭双向复制, 先使用单项复制进行模拟冲突的实验 2. 实验及其结果 诗檀软件 Oracle 数据库健康检查报告 3
2.1 模拟 update 冲突 2.1.1 没有任何冲突解决程序 首先源端先执行 update 语句, 先不提交 然后目标端执行 update 语句, 并提交 最后源端提交,stream 会把源端此事物 LCR 传递到目标端应用 目标端查询 发现在目标端上应用事物被回滚,LCRs 移动到了一个错误的队列中 SELECT apply_name, source_database, local_transaction_id, error_message FROM DBA_APPLY_ERROR; 此时应用进程已经中止 在不处理错误的情况下, 可以重新启动应用进程 : select * from DBA_APPLY_ERROR-- 查看错误信息查看进程状态 : SELECT CAPTURE_NAME,QUEUE_NAME,RULE_SET_NAME,NEGATIVE_RULE_SET_NAME,STA 诗檀软件 Oracle 数据库健康检查报告 4
TUS FROM DBA_CAPTURE; SELECT apply_name, apply_captured, status FROM dba_apply; 启动进程 : exec dbms_apply_adm.start_apply(apply_name => 'apply_10g_2'); 现在出现了错误事物, 要么清除这个信息, 要么使用 print LCRS, 打印出相应的信息, 然后使用错误处理来重新执行这个事物 清除 : exec DBMS_APPLY_ADM.DELETE_ALL_ERRORS; 删除了所有应用进程的错误队列可以用 apply_name 参数指定单独的应用进程 -- 清除了错误后, 也就是人为的忽略这个错误, 但是可能数据就已经违反了逻辑 2. 1.2 使用错误处理程序 : 查询错误 LCR 中的信息 为了方便手动将数据修正回去, 其实这里可以写存储过程 这里是事后人工去修正错误 然后调用错误处理程序 execute DBMS_APPLY_ADM.EXECUTE_ALL_ERRORS(execute_as_user=>TRUE); 发现, 原本错误的事物重新执行了 诗檀软件 Oracle 数据库健康检查报告 5
然后调用错误处理程序 execute DBMS_APPLY_ADM.EXECUTE_ALL_ERRORS(execute_as_user=>TRUE); 发现, 原本错误的事物重新执行了 2.1.3 创建 update 的冲突解决程序首先添加一个决议字段 version 在源端 hr 用户下 : alter table test add(version number default 1 not null); 在目标端创建处理程序 : DECLARE cols DBMS_UTILITY.NAME_ARRAY; cols(1) := 'id'; cols(2) := 'name'; cols(3) :='version'; DBMS_APPLY_ADM.SET_UPDATE_CONFLICT_HANDLER( object_name => 'hr.test', method_name =>'OVERWRITE', resolution_column => 'version', column_list => cols); 诗檀软件 Oracle 数据库健康检查报告 6
在源端为 column_list 的字段打开附加日志 : 直接在数据库层面打开附件日志 ( 我这里测试并未手动打开附件日志, 参数冲突仍然解决, 应该是配置抽取进程对对象自动开启了附件日志 ) 再次模拟之前的过程 : 源端 : update test set name='ccc',version=version+1 where id=5; 先不提交 : 目标端 : update test set name='v' where id=5; commit; 现在源端事物提交, 目标端再次查询 : 事物冲突解决, 应为使用的是 overwrite, 所以覆盖了 其实并没使用决议列, 但是必须要配置 ( 注意, 决议列的值会自动同步 ) 再次用 MINIMUM 测试, 是一样的 注意如果定义的字段列表和对象一致, 是可以执行修改的 否则要先移除这个处理程序后重新建立 : DECLARE cols DBMS_UTILITY.NAME_ARRAY; cols(1) := 'id'; cols(2) := 'name'; cols(3) :='version'; DBMS_APPLY_ADM.SET_UPDATE_CONFLICT_HANDLER( object_name => 'hr.test', method_name =>NULL, resolution_column => 'version', column_list => cols); 诗檀软件 Oracle 数据库健康检查报告 7
DECLARE cols DBMS_UTILITY.NAME_ARRAY; cols(1) := 'id'; cols(2) := 'name'; DBMS_APPLY_ADM.SET_UPDATE_CONFLICT_HANDLER( object_name => 'hr.test', method_name =>'OVERWRITE', resolution_column => 'name', column_list => cols); 使用 overwrite 其实不需要一个经常变化的的决议列 例如此处 : 源端执行语句 : update test set name='123' where id=5; commit; 目标端本身值是不同的, 但是由于有冲突解决, 此时值被源端的值覆盖 诗檀软件 Oracle 数据库健康检查报告 8
查询相关 column list: COLUMN OBJECT_OWNER HEADING 'Table Owner' FORMAT A5 COLUMN OBJECT_NAME HEADING 'Table Name' FORMAT A12 COLUMN METHOD_NAME HEADING 'Method' FORMAT A12 COLUMN RESOLUTION_COLUMN HEADING 'Resolution Column' FORMAT A13 COLUMN COLUMN_NAME HEADING 'Column Name' FORMAT A30 SELECT OBJECT_OWNER, OBJECT_NAME, METHOD_NAME, RESOLUTION_COLUMN, COLUMN_NAME FROM DBA_APPLY_CONFLICT_COLUMNS ORDER BY OBJECT_OWNER, OBJECT_NAME, RESOLUTION_COLUMN; 2.1.4 模拟目标端找不到行记录的情况 ( 由于目标端 delete 或 update, 导致源端的 LCR 过来之后找不到行记录 ) 源端执行 :update test set name='bbb' where id =2; 先不提交 目标端执行 : update test set id=3 where id =2; commit; 诗檀软件 Oracle 数据库健康检查报告 9
现在应用进程挂起 创建一个自定义忽略错误的解决程序 : --- 忽略源端的 update,insert 发现目标不存在的 hander 1 和 1403, 交给错误处理程序 其他类型的错误或者错误处理程序无法处理的事物还是会回滚, 在 error 队列中, 进程中断 CREATE OR REPLACE PROCEDURE ignore_handler (any_lcr IN SYS.ANYDATA, error_stack_depth IN NUMBER, error_numbers IN DBMS_UTILITY.NUMBER_ARRAY, error_messages IN DBMS_UTILITY.UNCL_ARRAY) IS lcr SYS.LCR$_ROW_RECORD; i PLS_INTEGER; b_raise BOOLEAN := TRUE; i := any_lcr.getobject( lcr ); CASE lcr.get_command_type() WHEN 'INSERT' THEN IF error_numbers( 1 ) = 1 THEN b_raise := FALSE; END IF; WHEN 'DELETE' THEN 诗檀软件 Oracle 数据库健康检查报告 10
IF error_numbers( 1 ) = 1403 THEN b_raise := FALSE; END IF; END CASE; IF b_raise THEN RAISE_APPLICATION_ERROR( error_numbers( 1 ), error_messages( 1 ) ); END IF; DBMS_APPLY_ADM.SET_DML_HANDLER( object_name => 'hr.test', object_type => 'TABLE', operation_name => 'INSERT', error_handler => TRUE, user_procedure => 'strmadmin.ignore_handler', apply_name => 'apply_10g_2'); DBMS_APPLY_ADM.SET_DML_HANDLER( object_name => 'hr.test', object_type => 'TABLE', operation_name => 'UPDATE', error_handler => TRUE, user_procedure => 'strmadmin.ignore_handler', apply_name => 'apply_10g_2'); oracle 11g 可以使用 DBMS_APPLY_ADM.REMOVE_STMT_HANDLER( object_name => 'hr.test', 诗檀软件 Oracle 数据库健康检查报告 11
operation_name => 'UPDATE', handler_name => 'xxxx', apply_name => 'apply_10g_2'); 或者用 : exec DBMS_STREAMS_HANDLER_ADM.DROP_STMT_HANDLER('track_jobs'); 10g 使用 : DBMS_APPLY_ADM.SET_DML_HANDLER( object_name => 'hr.test', object_type => 'TABLE', operation_name => 'UPDATE', error_handler => false, user_procedure => NULL, apply_name => 'APPLY_10G_2'); 将过程置为 null 的方式移除 handler 查询 handler: select * from dba_apply_dml_handlers -- 注意如果 apply_name 为 null 那么移除的时候要使用 null DBMS_APPLY_ADM.ALTER_APPLY( apply_name => 'strep01_apply', remove_ddl_handler => true); 当 update 发现目标端值不存在的时候把命令改成 insert 插入原值或新值到目标端 : --Create Package create or replace package pkg_insert_if_1403 诗檀软件 Oracle 数据库健康检查报告 12
as TYPE emsg_array IS TABLE OF VARCHAR2(2000) INDEX BY BINARY_INTEGER; procedure proc_insert_if_1403 (message IN ANYDATA, error_stack_depth IN NUMBER, error_numbers IN DBMS_UTILITY.NUMBER_ARRAY, error_messages IN EMSG_ARRAY); END pkg_insert_if_1403; -- Create package body. create or replace package body pkg_insert_if_1403 as procedure proc_insert_if_1403 ( message IN ANYDATA, error_stack_depth IN NUMBER, error_numbers IN DBMS_UTILITY.NUMBER_ARRAY, error_messages IN EMSG_ARRAY) is LCR sys.lcr$_row_record; RC pls_integer; begin if error_numbers(1)=1403 then rc:=message.getobject(lcr); --lcr.set_values('new',lcr.get_values('old')); lcr.set_values('new',lcr.get_values('new')); -- 一般是用 update 后的新值插入到目标端 lcr.set_values('old',null); lcr.set_command_type('insert'); lcr.execute(true); end if; end proc_insert_if_1403 ; end pkg_insert_if_1403; 诗檀软件 Oracle 数据库健康检查报告 13
DBMS_APPLY_ADM.SET_DML_HANDLER( object_name => 'HR.test', object_type => 'TABLE', operation_name => 'UPDATE', error_handler => true, user_procedure => 'strmadmin.pkg_insert_if_1403.proc_insert_if_1403', apply_database_link => NULL, apply_name => 'APPLY_10G_2'); 测试, 目标端删除 id=2 的值, 然后源端更新 id 为 2 的记录 : 2.1.5 模拟违反唯一主键的情况 ( 由于目标端 insert 或者 update, 导致源端的 LCR 过来后违反约束的情况 ) 创建忽略唯一性错误的 DML 处理过程 : CREATE OR REPLACE PROCEDURE ignore_handler (any_lcr IN SYS.ANYDATA --error_numbers IN DBMS_UTILITY.NUMBER_ARRAY, -- error_messages IN DBMS_UTILITY.UNCL_ARRAY ) IS lcr SYS.LCR$_ROW_RECORD; i PLS_INTEGER; b_raise BOOLEAN := TRUE; 诗檀软件 Oracle 数据库健康检查报告 14
i := any_lcr.getobject( lcr ); CASE lcr.get_command_type() WHEN 'INSERT' THEN --IF error_numbers( 1 ) = 1 THEN b_raise := FALSE; -- END IF; WHEN 'DELETE' THEN -- IF error_numbers( 1 ) = 1403 THEN b_raise := FALSE; --end if; WHEN 'UPDATE' THEN --IF error_numbers( 1 ) = 1403 THEN b_raise := FALSE; -- END IF; END CASE; IF b_raise THEn null; END IF; 源端插入的 id=3 目标端存在 (id 是主键有唯一索引 ), 但是上面处理程序可以使得目标 端忽略不应用 诗檀软件 Oracle 数据库健康检查报告 15
虽然 update id=2 在目标端无法找到对应的行, 但是上面 MDL 做了 null 的处理, 这样目标端会忽略这个 LCR 3. stream 健康检查 sqlplus nolog spool tmpsrdc_streams_hc.html @streams_hc_12_1_0_1.sql -- 脚本在 MOS 上提供 exit streams_hc_10gr2.sql 4. 总结 诗檀软件 Oracle 数据库健康检查报告 16
5. 其他问题 还缺少一个完美解决各种冲突的自定义存储过程 5.1 未解决的问题 问题号问题描述解决方案日期 1 缺少存储过程自己写一个 已解决的问题 问题号问题描述解决方案解决日期 诗檀软件 Oracle 数据库健康检查报告 17
ParnassusData Corporation, Shanghai, GaoPing Road No. 733. China Phone: (+86) 400-690-3643 ParnassusData.com Copyright 2013, ParnassusData andor its affiliates. All rights reserved. This document is provided for information purposes only and the contents hereof are subject to change without notice. This document is not warranted to be error-free, nor subject to any other warranties or conditions, whether expressed orally or implied in law, or including implied warranties and conditions of merchantability or fitness for a particular purpose. We specifically disclaim any liability with respect to this document and no contractual obligations are formed either directly or indirectly by this document. This document may not be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without our prior written permission. Oracle and Java are registered trademarks of Oracle andor its affiliates. Other names may be trademarks of their respective owners. AMD, Opteron, the AMD logo, and the AMD Opteron logo are trademarks or registered trademarks of Advanced Micro Devices. Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks are used under license and are trademarks or registered trademarks of SPARC International, Inc. UNIX is a registered trademark licensed through XOpen Company, Ltd. 0410 Copyright 2015ParnassusData Corporation. All Rights Reserved. 诗檀软件 Oracle 数据库健康检查报告 18