Oracle迁移contact_history表丢失4400万条数据问题咨询
问题根因
缺失的4400万条数据并未丢失,始终留在源表中,是你的SQL逻辑存在两个硬伤,导致插入时没捞到这部分数据、后续校验也没统计到这部分数据:
- 等值匹配逻辑漏洞:
contact_dt是DATE类型(精确到秒),你循环里用ch.contact_dt = dat做匹配时,dat是当日零点的日期值。只要字段里存了带非零时、分、秒的记录(比如2022-03-04 10:23:45、2022-06-05 18:12:09),就无法和零点值做等值匹配,这部分记录直接被插入逻辑过滤。 - 校验SQL本身写错:一方面你手滑把校验的起始年份从2022写成了2021,范围逻辑和迁移范围不匹配;另一方面结束时间只写了2022年6月5日零点,所有6月5日当天带时分秒的记录都满足
contact_dt > 2022-06-05 00:00:00,被校验条件排除。最终你查到的12亿条,只是所有contact_dt恰好是当日零点的记录,差的4400万就是带时分秒的那部分。 - 额外的脚本问题:你写的SELECT并行Hint是失效的——
SELECT -- + parallel(16)用了行注释--,且--和+之间有空格,数据库不会识别这个并行提示,只会拖慢迁移速度,不会导致丢数。
快速验证
执行下面两个SQL就能确认问题,第一个SQL的返回值就是你缺失的4400万左右:
-- 统计contact_dt带非零时分秒的记录总量 SELECT COUNT(*) FROM CONTACT_HISTORY WHERE contact_dt <> TRUNC(contact_dt); -- 查看源表contact_dt的实际时间边界 SELECT MIN(contact_dt), MAX(contact_dt) FROM CONTACT_HISTORY;
正确迁移方案
12亿+量级的数据没必要用按日循环的PL/SQL,直接开并行DML一次性迁移效率最高,也不会漏数,步骤如下:
- 先清空测试表,避免重复数据
TRUNCATE TABLE CONTACT_HISTORY_TEST;
- 开启会话级并行DML权限,执行迁移
ALTER SESSION ENABLE PARALLEL DML; INSERT /*+ APPEND PARALLEL(ct, 16) */ INTO CONTACT_HISTORY_TEST ct SELECT /*+ PARALLEL(ch, 16) */ ch.sas_contact_id, ch.contact_source, ch.client_id, ch.contact_dttm, ch.contact_dt, ch.sas_contact_error_desc, ch.sas_contact_status FROM CONTACT_HISTORY ch WHERE ch.contact_dt >= TO_DATE('04.03.2022', 'dd.mm.yyyy') AND ch.contact_dt < TO_DATE('06.06.2022', 'dd.mm.yyyy'); -- 注意结束时间写目标截止日的下一天零点,用<匹配,自动覆盖所有带时分秒的当日记录,避免漏数 COMMIT;
- 用正确的边界逻辑做数据校验
-- 源表统计 SELECT COUNT(*) FROM CONTACT_HISTORY WHERE contact_dt >= TO_DATE('04.03.2022', 'dd.mm.yyyy') AND contact_dt < TO_DATE('06.06.2022', 'dd.mm.yyyy'); -- 目标表统计 SELECT COUNT(*) FROM CONTACT_HISTORY_TEST WHERE contact_dt >= TO_DATE('04.03.2022', 'dd.mm.yyyy') AND contact_dt < TO_DATE('06.06.2022', 'dd.mm.yyyy');
如果你一定要保留按日循环的写法,只需要把插入条件改成TRUNC(ch.contact_dt) = dat即可,但性能会远低于一次性并行迁移。
内容的提问来源于stack exchange,提问作者Andrey Romanov
相关产品推荐
相关产品推荐

