在oracle中使用大量数据在同一个表中进行字段比较的最快方法

时间:2013-12-26 17:28:40

标签: oracle performance large-data

我从一个部门的csv文件中收到信息,与不同部门的相同信息进行比较,以检查是否存在差异(每行约44个列中约有3/4行数据)。在表格中有数据之后,我有一个程序可以获取数据并根据总部发送报告。我觉得我这样做的方式不是最有效的。我正在使用oracle进行比较。

这就是我所拥有的:

  • 我有一个vb.net程序解析数据并将其插入提取表

  • 我运行一个程序,将两个表上的完全外连接转换为一个新表,其中一个部门中的字段以“_c”为前缀

  • 我运行另一个程序来比较旧/新数据,并使用详细信息和摘要信息更新2个不同的表。以下是程序内部的代码:

    DECLARE 
      CURSOR Cur_Comp IS SELECT * FROM T.AEC_CIS_COMP;
    BEGIN 
    FOR compRow in Cur_Comp LOOP
    
        --If service pipe exists in CIS but not in FM and the service pipe has status of retired in CIS, ignore the variance
        If(compRow.pipe_num = '' AND cis_status_c = 'R')
            continue
        END IF
    
        --If there is not a summary record for this HQ in the table for this run, create one
        INSERT INTO t.AEC_CIS_SUM (HQ, RUN_DATE)
        SELECT compRow.HQ, to_date(sysdate, 'DD/MM/YYYY') from dual WHERE NOT EXISTS
        (SELECT null FROM t.AEC_CIS_SUM WHERE HQ = compRow.HQ AND RUN_DATE = to_date(sysdate, 'DD/MM/YYYY'))
    
        -- Check fields and update the tables accordingly
        If (compRow.cis_loop <> compRow.cis_loop_c) Then
            --Insert information into the details table
            INSERT INTO T.AEC_CIS_DET( Fac_id, Pipe_Num, Hq, Address, AutoUpdatedFl, 
                                                  DateTime, Changed_Field, CIS_Value, FM_Value)
            VALUES(compRow.Fac_ID, compRow.Pipe_Num, compRow.Hq, compRow.Street_Num || ' ' || compRow.Street_Name,
                   'Y', sysdate, 'Cis_Loop', compRow.cis_loop, compRow.cis_loop_c); 
    
            -- Update information into the summary table        
            UPDATE AEC_CIS_SUM                 
            SET cis_loop = cis_loop + 1
            WHERE Hq = compRow.Hq
              AND Run_Date = to_date(sysdate, 'DD/MM/YYYY')               
        End If;       
    END LOOP;
    

    END;

对于表格的所有44列,更简单的方法而不是if语句的任何建议? (如果重要的话,每周运行一次)

更新:为了澄清,有88列数据(44个重复项与一个后缀为_c的重复项)。一个表列出了一行中不同的每个字段,因此一行可以表示在该表中写入的30多个记录。另一张表记录了每周的差异数量。

2 个答案:

答案 0 :(得分:2)

首先,我相信您的任务可以使用staight SQL实现(并且应该实际)。没有花哨的游标,没有循环,只是选择,插入和更新。我会先解开你的源数据(你不清楚你是否有主键加入两套,我猜你这样做了):

Col0_PK    Col1    Col2    Col3    Col4
----------------------------------------
Row1_val   A       B       C       D
Row2_val   E       F       G       H

以上是您的源数据。使用UNPIVOT clause我们将其转换为:

Col0_PK     Col_Name    Col_Value
------------------------------
Row1_val    Col1        A
Row1_val    Col2        B
Row1_val    Col3        C
Row1_val    Col4        D
Row2_val    Col1        E
Row2_val    Col2        F
Row2_val    Col3        G
Row2_val    Col4        H

我想你明白了。假设我们有一组带有一组数据的table1和带有第二组数据的相同结构化table2。最好使用索引组织表。

下一步是将行相互比较并存储差异细节。类似的东西:

insert into diff_details(some_service_info_columns_here)
 select some_service_info_columns_here_along_with_data_difference
  from table1 t1 inner join table2 t2
     on t1.Col0_PK = t2.Col0_PK
    and t1.Col_name = t2.Col_name
    and nvl(t1.Col_value, 'Dummy1') <> nvl(t2.Col_value, 'Dummy2');

在最后一步,我们更新差异汇总表:

insert into diff_summary(summary_columns_here)
 select diff_row_id, count(*) as diff_count
  from diff_details
 group by diff_row_id;

只是粗略的草稿来展示我的方法,我确信还有更多的细节应该被考虑在内。总结一下,我建议两件事:

  1. UNPIVOT数据
  2. 使用SQL语句代替游标

答案 1 :(得分:0)

您的代码中有几个问题:

If(compRow.pipe_num = '' AND cis_status_c = 'R')
    continue
END IF

未声明“cis_status_c”。它是AEC_CIS_COMP中的变量还是列? 如果它是一列,只需将条件放入光标,即SELECT * FROM T.AEC_CIS_COMP WHERE not (compRow.pipe_num = '' AND cis_status_c = 'R')

to_date(sysdate, 'DD/MM/YYYY')

这是胡说八道,您将日期转换为日期,只需使用TRUNC(SYSDATE)

即可

无论如何,我认为您可以使用三个单个语句而不是游标:

INSERT INTO t.AEC_CIS_SUM (HQ, RUN_DATE)
SELECT comp.HQ, trunc(sysdate)
from AEC_CIS_COMP comp
WHERE NOT EXISTS
    (SELECT null FROM t.AEC_CIS_SUM WHERE HQ = comp.HQ AND RUN_DATE = trunc(sysdate));


INSERT INTO T.AEC_CIS_DET( Fac_id, Pipe_Num, Hq, Address, AutoUpdatedFl, DateTime, Changed_Field, CIS_Value, FM_Value)
select comp.Fac_ID, comp.Pipe_Num, comp.Hq, comp.Street_Num || ' ' || comp.Street_Name, 'Y', sysdate, 'Cis_Loop', comp.cis_loop, comp.cis_loop_c
from T.AEC_CIS_COMP comp
where comp.cis_loop <> comp.cis_loop_c;

UPDATE AEC_CIS_SUM                 
SET cis_loop = cis_loop + 1
WHERE Hq IN (Select Hq from T.AEC_CIS_COMP)
  AND trunc(Run_Date) = trunc(sysdate);

他们没有经过测试,但他们应该给你一个如何做的提示。