【问题标题】:Can we perform Merge like operation in bulk?我们可以批量执行类似合并的操作吗?
【发布时间】:2021-08-28 10:06:29
【问题描述】:

我们有一个接收 200 条自定义类型记录的过程。 使用 For 循环将这些记录插入到表 XYZ 中。

(不幸的是,这个 XYZ 表没有任何主键,它有大约 650 万条记录)。 现在,一旦插入完成,就会执行删除操作。

现有代码:-

PROCEDURE XXX_FIN_INSERT_DATA_PRC_YYY_AP (p_in_YYY_AP XXX_FIN_YYY_AP_TYPE_V2) IS
  test_gl_t XXX_FIN_YYY_AP_TYPE_V2;
  BEGIN
  test_gl_t := p_in_YYY_AP;

  FOR i IN test_gl_t.FIRST .. test_gl_t.LAST
  LOOP
    INSERT
    INTO XXX_FIN_YYY_AP_TBL(
          DOC_TYPE          
        ,VENDOR_NAME       
        ,SUPPLIER_SEGMENT1 
        ,INVOICE_NUMBER    
        ,INVOICE_DATE        
        ,INVOICE_AMOUNT    
        ,COST_CENTER       
        ,PO_HEADER_SEGMENT1
        ,CHECK_NUMBER      
        ,CHECK_DATE        
        ,CHECK_AMOUNT      
        ,INVOICE_ID        
        ,CHECK_ID          
        ,DIST_AMOUNT       
        ,FILE_ID           
        ,XXX_RECORD_ID     )
      VALUES
      (
        test_gl_t (i).DOC_TYPE          
        ,test_gl_t (i).VENDOR_NAME       
        ,test_gl_t (i).SUPPLIER_SEGMENT1 
        ,test_gl_t (i).INVOICE_NUMBER    
        ,test_gl_t (i).INVOICE_DATE      
        ,test_gl_t (i).INVOICE_AMOUNT    
        ,test_gl_t (i).COST_CENTER       
        ,test_gl_t (i).PO_HEADER_SEGMENT1
        ,test_gl_t (i).CHECK_NUMBER      
        ,test_gl_t (i).CHECK_DATE        
        ,test_gl_t (i).CHECK_AMOUNT      
        ,test_gl_t (i).INVOICE_ID        
        ,test_gl_t (i).CHECK_ID          
        ,test_gl_t (i).DIST_AMOUNT       
        ,test_gl_t (i).FILE_ID 
        ,XXX_FIN_JOURNALS_REC_SEQ.NEXTVAL);

    DELETE FROM XXX_FIN_YYY_AP_TBL WHERE 
    DOC_TYPE = test_gl_t (i).DOC_TYPE
    AND VENDOR_NAME = test_gl_t (i).VENDOR_NAME
    AND SUPPLIER_SEGMENT1 = test_gl_t (i).SUPPLIER_SEGMENT1 
    AND INVOICE_NUMBER = test_gl_t (i).INVOICE_NUMBER
    AND INVOICE_DATE = test_gl_t (i).INVOICE_DATE   
    AND COST_CENTER = test_gl_t (i).COST_CENTER 
    AND CHECK_NUMBER = test_gl_t (i).CHECK_NUMBER
    AND CHECK_DATE = test_gl_t (i).CHECK_DATE
    AND INVOICE_ID = test_gl_t (i).INVOICE_ID
    AND CHECK_ID = test_gl_t (i).CHECK_ID 
    AND FILE_ID < test_gl_t (i).FILE_ID;

    END LOOP;
  END XXX_FIN_INSERT_DATA_PRC_YYY_AP;

我尝试将其修改为:-

PROCEDURE XXX_FIN_INSERT_DATA_PRC_YYY_AP_NEW (p_in_YYY_AP XXX_FIN_YYY_AP_TYPE_V2)
     IS
  test_gl_t XXX_FIN_YYY_AP_TYPE_V2;
  TYPE temp_table_type is TABLE of XXX_FIN_YYY_AP_TBL%ROWTYPE INDEX BY PLS_INTEGER;
  temp_table temp_table_type;
  CURSOR c is SELECT * FROM XXX_FIN_YYY_AP_TBL ORDER BY INVOICE_ID DESC;
  
  BEGIN
  test_gl_t := p_in_YYY_AP;
  OPEN c;
  FETCH c BULK COLLECT INTO temp_table LIMIT 5000; 
    LOOP
        FOR idx IN 1..temp_table.LAST LOOP
            FOR i IN test_gl_t.FIRST .. test_gl_t.LAST LOOP
                    IF (    temp_table(idx).DOC_TYPE = test_gl_t(i).DOC_TYPE
                        AND temp_table(idx).VENDOR_NAME = test_gl_t(i).VENDOR_NAME
                        AND temp_table(idx).SUPPLIER_SEGMENT1 = test_gl_t(i).SUPPLIER_SEGMENT1 
                        AND temp_table(idx).INVOICE_NUMBER = test_gl_t(i).INVOICE_NUMBER
                        AND temp_table(idx).INVOICE_DATE = test_gl_t(i).INVOICE_DATE    
                        AND temp_table(idx).COST_CENTER = test_gl_t(i).COST_CENTER 
                        AND temp_table(idx).CHECK_NUMBER = test_gl_t(i).CHECK_NUMBER
                        AND temp_table(idx).CHECK_DATE = test_gl_t(i).CHECK_DATE
                        AND temp_table(idx).INVOICE_ID = test_gl_t(i).INVOICE_ID
                        AND temp_table(idx).CHECK_ID = test_gl_t(i).CHECK_ID 
                        AND temp_table(idx).FILE_ID < test_gl_t(i).FILE_ID) THEN
                        
                        INSERT INTO XXX_FIN_YYY_AP_TBL (
                                DOC_TYPE,VENDOR_NAME,SUPPLIER_SEGMENT1,INVOICE_NUMBER,INVOICE_DATE,INVOICE_AMOUNT
                                ,COST_CENTER,PO_HEADER_SEGMENT1,CHECK_NUMBER,CHECK_DATE,CHECK_AMOUNT,INVOICE_ID
                                ,CHECK_ID,DIST_AMOUNT,FILE_ID,XXX_RECORD_ID
                                )
                        VALUES
                        (
                            test_gl_t(i).DOC_TYPE          
                            ,test_gl_t(i).VENDOR_NAME       
                            ,test_gl_t(i).SUPPLIER_SEGMENT1 
                            ,test_gl_t(i).INVOICE_NUMBER    
                            ,test_gl_t(i).INVOICE_DATE       
                            ,test_gl_t(i).INVOICE_AMOUNT    
                            ,test_gl_t(i).COST_CENTER       
                            ,test_gl_t(i).PO_HEADER_SEGMENT1
                            ,test_gl_t(i).CHECK_NUMBER      
                            ,test_gl_t(i).CHECK_DATE        
                            ,test_gl_t(i).CHECK_AMOUNT      
                            ,test_gl_t(i).INVOICE_ID        
                            ,test_gl_t(i).CHECK_ID          
                            ,test_gl_t(i).DIST_AMOUNT       
                            ,test_gl_t(i).FILE_ID 
                            ,XXX_FIN_JOURNALS_REC_SEQ.NEXTVAL
      );
            END IF;     
            END LOOP;
        END LOOP;
  EXIT WHEN c%notfound;
  END LOOP;
  CLOSE c;
  
    
  END XXX_FIN_INSERT_DATA_PRC_YYY_AP_NEW;

我运行了调用我的过程的主服务。 服务挂了。 现在当我在我的代码中添加调试语句并尝试编译 SQL Developer 时挂起。 我重新启动了很多次,但我无法恢复。

我请求 DBA 对此提供帮助。

现在我向专家提出的问题是:-

  • 我写的代码有什么问题?有更好的方法吗?
  • 我也为该表编制了索引,但我想知道是否有 更好的解决方案。

任何建议/讨论/提示都会有所帮助。

问候, 德布

【问题讨论】:

    标签: sql oracle query-optimization bulkinsert


    【解决方案1】:

    试试这个:

    FORALL i IN INDICES OF p_in_YYY_AP 
    INSERT INTO XXX_FIN_YYY_AP_TBL (...) 
    VALUES (
       p_in_YYY_AP(i).DOC_TYPE ,
       ...);
    
    FORALL i IN INDICES OF p_in_YYY_AP 
    DELETE FROM XXX_FIN_YYY_AP_TBL 
    WHERE DOC_TYPE = p_in_YYY_AP(i).DOC_TYPE
       AND ...;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      • 2021-01-10
      • 1970-01-01
      • 1970-01-01
      • 2015-05-28
      • 2013-07-02
      相关资源
      最近更新 更多