暂无图片
暂无图片
5
暂无图片
暂无图片
暂无图片

Oracle两表数据不一致的补数操作

639

Part1 环境信息

源库和目的库都是Oracle 11GR2

Part2 问题信息

目的库创建模拟表

create table A_test(
id nvarchar2(200), 
name nvarchar2(200), 
age integer, 
password nvarchar2(200)
);

alter table A_test add constraint A_test_id primary key (id,name);


-- 插入1000的模拟数据
 
INSERT INTO A_test (id, name, age, password)
SELECT
    'id'||FLOOR(DBMS_RANDOM.value(0, 10000)),  -- 生成随机的ID
    'User'||FLOOR(DBMS_RANDOM.value(0, 10000)),  -- 生成随机的用户名
    FLOOR(DBMS_RANDOM.value(18, 118)),  -- 生成随机的年龄 (18-117)
    'user'||FLOOR(DBMS_RANDOM.value(0, 10000)) ||'@example.com'-- 生成随机的邮箱地址
FROM
    dual
CONNECT BY LEVEL <=1000;

模拟创建源库的抽取表,

我一般是通过数据泵来迁移这个表,这里只是模拟

create table B_test as select * from A_test;

模拟A_test缺数

delete from A_test where rownum < 200;
commit;

select count(*) from A_test;
801

select count(*) from B_test;
1000

Part3 问题模拟

3.1、OGG定位源库目的库信息

登录OGG

./ggsci

查看所有信息OGG进程信息

GGSCI () 1>  info all

查看连接信息group

GGSCI () 1>  view params ECA2

定位带table的行,确认有需要同步的问题表

找到问题表再找连接数据库信息

GGSCI () 1>  view params ECA2
userid 用户@tns信息, password 密码

找到userid开头的行,通过@后边的关键字
find / -name tnsnames.ora

cat tnsnames.ora

通过目的端的info进程来判断源端的进程数据库信息

3.2、OGG定位源库目的库信息

直接问业务人员也行

Part4 问题解决

4.1、IGNORE_ROW_ON_DUPKEY_INDEX倒数(适合不超过2千万的数据)

INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(A_test(id,name))  parallel(16) */
INTO A_test
  select * from B_test;
commit;

模拟两表列不一致的情况,记得把列写清楚

INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(A_test(id,name))  parallel(16) */
INTO A_test
  select id,name,age,password from B_test;
commit;

比较数量,如果数量不对,还可以在执行几次

select count(*) from A_test;

1000

4.2、NOT EXISTS倒数(两个表分别的数据超过2千万)

再次模拟删除数据

delete from A_test where rownum < 200;
commit;

创建缺数据备份表

CREATE TABLE B_test_bak AS
SELECT B_test.*
FROM B_test
WHERE NOT EXISTS (
    SELECT 1
    FROM A_test
    WHERE A_test.id = B_test.id
      AND A_test.name = B_test.name
);

这样插入

INSERT INTO /*+ parallel(8) */ A_test
  select * from B_test_bak;
commit;
INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(A_test(id,name))  parallel(16) */
INTO A_test
  select id,name,age,password,sysdate from B_test;
commit;

必须要这么做,因为当表的数据量很大的时候,不管是检索的时间长,还是undo表空间,都无法承受这样的消耗负担。 我在生产库尝试直接用IGNORE_ROW_ON_DUPKEY_INDEX插入数据,导致62G得undo表空间都不够用了。

Part5 原理

在Oracle数据库中,MINUS 操作符用于返回两个查询结果之间的差异。具体来说,它返回第一个查询中存在而第二个查询中不存在的行。这在你需要找出一个数据集与另一个数据集之间的差异时非常有用。
IGNORE_ROW_ON_DUPKEY_INDEX:忽略唯一约束冲突,回滚当前行(这个是导致UNDO表空间增长的主要原因),继续完成其他行的插入。

Part6 题外话

AI建议我用 minus、left join和not exist,但是感觉minus的局限性比较强,做列少的表,比较合适,而且要熟悉表信息,个人感觉不太实用。
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论