- DBA攻坚指南:左手Oracle,右手MySQL
- 叶桦 徐浩 张梦颖 应以峰
- 1758字
- 2021-07-09 20:30:16
3.6 如何保证数据一致性
保证迁移前后的数据一致性是一件至关重要的事,如果这一条底线都无法满足,别的就更无从谈起了。百分之八九十的物理迁移都能保证数据一致性,但也不排除因为内部一些自动任务或外部连接所引起的数据变更,而导致的数据不一致。相较于物理迁移,逻辑迁移导致数据不一致的概率则要高很多。本着对客户负责的原则,DBA如何用事实来证明迁移前后的数据一致性是本节讨论的重点。
接下来,我们将介绍三种检查数据一致性的方法。
1.Oracle GoldenGate Veridata
Veridata不仅可用于检查数据的不一致,而且能在数据不一致的情况下进行修复,关于Veridata的具体介绍和配置方法请参考3.5.3节,下面就来演示如何使用Veridata修复不一致的数据。图3-3所示的是作业jtest的比对情况,虽然作业已成功执行,但存在数据不一致的问题。
当检测到数据不同步时,Veridata将报告出数据不一致的情况,并提供修复选项。查看jtest的比对结果,我们可以看到有一张表的数据不同步。可以通过单击该作业运行的“Compare Pairs Out-Of-Sync”中的超链接来查看不同步的详细信息,超链接的具体信息如图3-4所示。
如图3-5所示,Veridata已检测到不同步的情况。对于修复,这里提供了两种方法,分别为生成修复SQL和直接在页面上修复。
图3-3 作业完成后的比对情况
图3-4 表数据不同步的具体情况
图3-5 不同步数据的修复方法
如果点击“Generate SQL”,则会在Veridata服务器/tmp目录下生成一个以作业名为前缀的压缩(格式为zip)包。
shell> ls -rtl jtest* -rw-r----- 1 oracle oinstall 23710 Jul 25 09:43 jtest1595641348119.zip
修复时只需要将解压出来的SQL文本传至目标端数据库执行即可。
另一种方法是直接单击“run repair”(运行修复),修复完成后,状态(STATUS)变为绿色,如图3-6所示。
图3-6 不同步数据修复后的情况
查看最新的同步状态,建议重新执行一次作业,以便再次获取同步报告。
如果无法使用Veridata,我们也可以使用行数对比和DBMS_COMPARE包的方式,但这两种方式在遇到数据不一致问题的时候需要手动处理。
2.行数对比
在数据准确性方面,行数对比方式没有其他两种方式高,如果系统繁忙,那么行数差异的问题永远都会存在。
使用这种方法需要在系统用户下创建对比表格,定义如下:
SQL> CREATE TABLE ODC.ROW_COUNT_STATS (SCHEMANAME VARCHAR2(30 BYTE), TABLENAME VARCHAR2(30 BYTE), ROW_CNT_SOURCE NUMBER, ROW_CNT_TARGET NUMBER, CNT_DIFF NUMBER);
还需要额外创建连接源端的DBLINK,命令如下:
SQL> CREATE PUBLIC DATABASE LINK OGGLINK CONNECT TO ODC IDENTIFIED BY odc USING '(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.238.131)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = joe) ) )';
之后将需要比对的用户和表插入新创建的TABLE_LIST表中,命令如下:
SQL> CREATE TABLE ODC.TABLE_LIST (SCHEMANAME VARCHAR2(30 BYTE), TABLENAME VARCHAR2(30 BYTE)); <!--插入对比表格--> SQL> select * from ODC.TABLE_LIST; SCHEMANAME TABLENAME ------------------------------ ------------------------------ SCOTT TEST1 SCOTT SALGRADE SCOTT BONUS SCOTT EMP SCOTT DEPT
使用下面的命令比对数据是否一致:
SQL> declare v_schemaname varchar2(60); v_tablename varchar2(60); v_tarcount NUMBER(16) := 0; v_srccount NUMBER(16) := 0; v_sql1 varchar2(2000); v_sql2 varchar2(2000); v_sql3 varchar2(2000); v_cntdiff NUMBER(16) := 0; cursor cur_tablist is select SCHEMANAME,TABLENAME from ODC.TABLE_LIST; begin open cur_tablist; loop fetch cur_tablist into v_schemaname,v_tablename; exit when cur_tablist%notfound; v_sql1 := 'select count(*) from ' || v_schemaname ||'.'|| v_tablename || ''; execute immediate v_sql1 into v_tarcount; v_sql2 := 'select count(*) from ' || v_schemaname ||'.'|| v_tablename || '@OGGLINK'; execute immediate v_sql2 into v_srccount; v_cntdiff :=v_tarcount - v_srccount; v_sql3 := 'insert into ODC.ROW_COUNT_STATS (schemaname,tablename, row_cnt_source,row_cnt_target,cnt_diff) values ('''||upper(v_ schemaname)||''','''||v_tablename||''',' || v_srccount || ',' || v_tarcount || ',' || v_cntdiff || ')'; execute immediate v_sql3; end loop; close cur_tablist; end; /
完成后,可以在ROW_COUNT_STATS表中生成报告,以确定是否存在差异。根据该表的CNT_DIFF列结果进行判断,如果是0,则表示数量一致,如果不为0,则表示两端数据存在差异。示例代码如下:
SQL> select * from ODC.ROW_COUNT_STATS ; SCHEMANAME TABLENAME ROW_CNT_SOURCE ROW_CNT_TARGET CNT_DIFF --------------- ---------- -------------- -------------- ---------- SCOTT TEST1 86507 86507 0 SCOTT SALGRADE 5 5 0 SCOTT BONUS 0 0 0 SCOTT EMP 14 14 0 SCOTT DEPT 4 4 0
3.使用DBMS_COMPARE包
执行数据验证的另一种替代方法是,使用数据库内置的DBMS_COMPARE包,此方法使用哈希逐行比对,速度上没有其他两种方式快,而且无法用于LOB(大对象)数据类型和没有主键的表。有关DBMS_COMPARE的其他限制,可以查阅Oracle官方文档《Database PL/SQL Packages and Types Reference》获取更多信息。
DBMS_COMPARE包进行数据验证的具体使用步骤如下。
1)创建比较任务。
2)执行比较任务。
3)手动修复不一致的数据。
此处仅比较scott用户下的emp表,创建任务的命令如下:
SQL> BEGIN DBMS_COMPARISON.CREATE_COMPARISON( comparison_name => 'SCOTT_EMP_COMPARE', schema_name => 'SCOTT', object_name => 'EMP', dblink_name => 'OGGLINK'); END; /
上述代码段中的参数说明如下。
·comparison_name:自定义对比名称。
·dblink_name:目标端与源端数据库连接。
带入创建的自定义名称SCOTT_EMP_COMPARE,执行比较任务,命令如下:
SQL> SET SERVEROUTPUT ON SQL> DECLARE consistent BOOLEAN; compare_info DBMS_COMPARISON.COMPARISON_TYPE; BEGIN consistent := DBMS_COMPARISON.COMPARE( comparison_name => 'SCOTT_EMP_COMPARE', scan_info => compare_info, perform_row_dif => TRUE ); DBMS_OUTPUT.PUT_LINE('Scan ID: '||compare_info.scan_id); IF consistent=TRUE THEN DBMS_OUTPUT.PUT_LINE('The table is equivalent'); ELSE DBMS_OUTPUT.PUT_LINE('Tables are not equivalent… there is data divergence.'); DBMS_OUTPUT.PUT_LINE('Check the dba_comparison and dba_comparison_scan_summary views for locate the differences for compare_id:'||compare_info.scan_id); END IF; END; / Scan ID: 1 Tables are not equivalent there is data divergence. Check the dba_comparison and dba_comparison_scan_summary views for locate the differences for compare_id:2
在上述代码中,not equivalent程序包检测到数据差异,并记录到系统视图DBA_COMPARISON、DBA_COMPARISON_SCAN_SUMMARY和DBA_COMPARISON_ROW_DIF中。接下来查询DBA_COMPARISON_ROW_DIF,以确认不同步的数据(如图3-7所示)。
图3-7 整体查询不同步的数据
然后,通过图3-7中返回的rowid查询具体的数据,结果如图3-8所示。
图3-8 具体查询不同步的数据
查明差异行数据之后,最后一步就是修复了,我们可以在删除目标端差异数据之后再重新插入,实现方法有很多种,这里就不做展开了,大家可以根据自身的实际情况选择以上三种方式中的任意一种,强烈建议选择第一种方式,因为不管是准确性还是效率,Oracle GoldenGate Veridata都是最高的。