zoukankan      html  css  js  c++  java
  • ODI中删除数据的处理

     

    一、前提知识:
    数据从源数据库向数据仓库抽取时,一般采用以下几种方式:

    • 全抽取模式
      如果表的数据量较小,则可以采取全表抽取方式,以TRUNCATE/INSERT方式进行数据抽取。
    • 基于时间戳的抽取模式
      如果源数据表是不可更新的数据(如大多数事务处理数据)或者是不可删除数据(只能失效历史记录的情况),则根据变更时间戳,抽取最新变更的数据进行同步。
    • 日志分析
      如果没有更新时间戳,或者源数据存在删除的情况,则可以进行日志分析,来执行最新数据变更的同步。

    说明:时间戳的方式如果要处理删除数据的情况,需要在源表创建触发器来捕获删除的记录。
    ODI在数据抽取方面,添加了CDC(Changed Data Capture)的功能,并且包含两种方式,一种是在源数据库表上增加触发器来捕获新增、修改和删除的数据到日志表中。另一种是通过对日志的挖掘(Oracle的Log Miner和IBM DB2/400)。但是ODI的CDC,必须要求源表有主键。
    二、删除数据的问题引入
    当我们开始使用ODI来进行CDC方式的数据同步时,一切都正常,删除的数据也可以正确的同步到目标数据库。接着,因为业务需求,我们只需要同步部分数据到目标数据库,也就是为源数据表加上过滤,这样问题就出来了,新增和修改的数据都能正确的同步到目标数据库,而源数据表删除的数据,经过ODI Interface执行之后,目标数据表中还存在。
    经过检查,Interface在装载数据时查询日志视图,而日志视图是日志表与源表的外连接,其结果是删除的记录在视图中只有主键,其余的字段都为空,这样基于日志视图上的过滤,必然导致删除的数据被过滤掉。以下是ODI创建的对象脚本示例:

    数据源日志视图jv$qp_list_lines
    create or replace view soau.jv$qp_list_lines as
    SELECT decode(targ.ROWID, NULL, 'D', 'I') jrn_flag,
           jrn.jrn_subscriber jrn_subscriber,
           jrn.jrn_date jrn_date,
           jrn.list_line_id list_line_id,
           targ.creation_date creation_date,
           targ.created_by created_by,
           ...
    FROM (SELECT l.jrn_subscriber jrn_subscriber, l.list_line_id list_line_id, MAX(l.jrn_date) jrn_date
    FROM soau.j$qp_list_lines l
    WHERE l.jrn_consumed = '1'
    GROUP BY l.jrn_subscriber, l.list_line_id) jrn,
    soau.qp_list_lines targ
    WHERE jrn.list_line_id = targ.list_line_id(+)

    ODI Interface创建用于装载数据的的临时视图
    create or replace view
    SOAU.C$_0QP_LIST_LINES
    (
    C1_LIST_LINE_ID,
    C2_CREATION_DATE,
    C3_CREATED_BY,
    ...
    JRN_SUBSCRIBER,
    JRN_FLAG,
    JRN_DATE
    )
    as select
    QP_LIST_LINES.LIST_LINE_ID,
    QP_LIST_LINES.CREATION_DATE,
    QP_LIST_LINES.CREATED_BY,
    ...
    JRN_SUBSCRIBER,
    JRN_FLAG,
    JRN_DATE
    from SOAU.JV$QP_LIST_LINES QP_LIST_LINES
    where (1=1)
    And (QP_LIST_LINES.LIST_LINE_TYPE_CODE IN ('PLL', 'PBH'))
    And (QP_LIST_LINES.END_DATE_ACTIVE is null or trunc(QP_LIST_LINES.END_DATE_ACTIVE) > trunc(sysdate))
    And (QP_LIST_LINES.PRICING_PHASE_ID = 1)
    And (QP_LIST_LINES.QUALIFICATION_IND IN (4, 6, 20, 22))
    AND JRN_SUBSCRIBER = 'ERP-FK' /* AND JRN_DATE < sysdate */

    当 Interface在执行集成时,将数据从视图SOAU.C$_0QP_LIST_LINES插入到flow table(flow table是Interface处理的位于目标中间表,数据的同步最终从flow table到目标数据表),由于该视图已经执行了过滤,删除的数据就无法插入到flow table,导致删除的数据最终无法写入目标。
    三、问题解决过程
    因为数据在源头就被过滤了,所以必须保证数据在源头不被过滤,而Interface可以支持在源、Staging、目标来执行处理,那么就来做各种测试:
    1、将数据过滤移到Staging
    经过测试发现,虽然在装载数据时,包含了删除的记录,但是在集成阶段,数据插入flow table时,由于除了主键,其余字段都为空,所以删除的数据同样被过滤掉了。
    2、将数据过滤移到目标
    经过测试,当我们将过滤移到目标时,删除的数据被正确的同步到了目标表。那只要将过滤移到目标,就可以解决问题了?
    3、新问题的出现
    实际上数据插入flow table后,从flow table到目标表,没有执行任何过滤处理,所有数据都会被同步到目标数据表。这样我们需要排除的数据也写入了目标表,说明这个方式失败。
    4、启用模型中目标表的过滤
    在ODI Designer中,编辑Model下的表,添加过滤,然后将Interface中对源数据的过滤移除,执行Interface发现,数据正确的插入到了目标表。但是这种方式和前一种方式相同,都是把所有变化的数据都从源取到目标中,存在一定的性能问题。
    5、最终的方式
    经过研究,还是觉得修改ODI原来的LKM最为实际,只需要把从日志视图的取数的视图代码修改,修改为原来的视图代码UNION删除的记录即可。
    修改后的Create view on source代码如下:

    create or replace view <%=odiRef.getObjectNameDefaultPSchema("L", "" , "W")%><%=odiRef.getInfo("COLL_NAME")%>
    (
    <%=odiRef.getColList("", "[CX_COL_NAME]", ",/n/t", "", "")%>
    )
    as select <%=odiRef.getPop("DISTINCT_ROWS")%>
    <%=odiRef.getColList("", "[EXPRESSION]", ",/n/t", "", "")%>
    from <%=odiRef.getFrom()%>
    where (1=1)
    <%=odiRef.getFilter()%>
    <%=odiRef.getJrnFilter()%>
    <%=odiRef.getJoin()%>
    <%=odiRef.getGrpBy()%>
    <%=odiRef.getHaving()%>

    <%if(!odiRef.getJrnFilter().equals("")){%>

    UNION

    select <%=odiRef.getPop("DISTINCT_ROWS")%>
    <%=odiRef.getColList("", "[EXPRESSION]", ",/n/t", "", "")%>
    from <%=odiRef.getFrom()%>
    where (1=1)
    <%=odiRef.getJrnFilter()%>
    AND JRN_FLAG='D'
    <%=odiRef.getJoin()%>
    <%=odiRef.getGrpBy()%>
    <%=odiRef.getHaving()%>

    <%}%>
    四、插曲
    在问题有了解决方案之后,向Oracle提Tar,经过数次沟通,并最终在OWC演示的情况下,确认为KM的Bug。
    不过Oracle又提供了一种处理方法,这种方法不需要修改LKM,但是看上去感觉总有点不那么好:在Interface中的每个Filter代码中,加入" OR JRN_FLAG = 'D'",这样就可以保证日志表中删除的记录一定不会被过滤掉。

  • 相关阅读:
    网页导出PDF文件
    图片翻转导航
    瀑布流之ajax
    楼梯效果
    数码时钟
    数字字母随机验证码
    kafka shell
    zookeeper shell
    正则
    Linux(一)
  • 原文地址:https://www.cnblogs.com/lcword/p/5704233.html
Copyright © 2011-2022 走看看