简体   繁体   English

FORALL 在 BULK COLLECT 中的使用 PLSQL

[英]FORALL usage in BULK COLLECT in PLSQL

Hello I have a procedure and questions about it.您好,我有一个程序和有关它的问题。 This procedure is used for extracting data then inserting them into one table.此过程用于提取数据然后将它们插入到一个表中。 I realized that we dont use loop while in FORALL syntax.我意识到我们在 FORALL 语法中不使用循环。 So my purpose is that extracting 10.000 records then inserting these 10.000 records into a single table.所以我的目的是提取 10.000 条记录,然后将这 10.000 条记录插入到一个表中。 What I want to know is that, the procedure just stops after inserting 10.000 records or continues its' work?我想知道的是,该程序是在插入 10.000 条记录后停止还是继续其工作? I am asking because there is no loop inside FORALL?我问是因为 FORALL 里面没有循环吗? My second question is that should I remove v_cnt and IF MOD (v_cnt, 10000) = 0 lines in the script?我的第二个问题是我应该删除脚本中的 v_cnt 和 IF MOD (v_cnt, 10000) = 0 行吗?

I am adding scripts below, I am open to any fix advices or anything else thank you from now.我在下面添加脚本,从现在开始我愿意接受任何修复建议或任何其他感谢。

    create or replace procedure GPU_DATA_EXTRACTOR_TEST(pid_billdate DATE) is
v_cnt      NUMBER;
c_limit   CONSTANT PLS_INTEGER DEFAULT 10000;

CURSOR c1 IS
SELECT DISTINCT intl_prod_id
      FROM apld_bill_rt abr,
           acct_bill ab
      WHERE abr.CHRG_TP = 'INSTALLMENT'
          AND abr.TAX_CATG_ID = 'NOTAX'
          AND abr.acct_bill_id = ab.acct_bill_id
          AND ab.bill_date = pid_billdate;

TYPE prod_ids_t IS TABLE OF apld_bill_rt.intl_prod_id%TYPE INDEX BY PLS_INTEGER;
l_prod_ids   prod_ids_t;
begin

   execute immediate 'truncate table GPU_INV_TEST';

   v_cnt := 0;
  OPEN c1;

  LOOP
     FETCH c1 BULK COLLECT INTO l_prod_ids LIMIT c_limit;
     
     EXIT WHEN l_prod_ids.COUNT = 0;

    FORALL indx IN 1 .. l_prod_ids.COUNT
    
      INSERT INTO GPU_INV_TEST
         SELECT AB.ACCT_BILL_ID,
                AB.BILL_NO,
                AB.INV_ID,
                AB.BILL_DATE,
                ba2.bill_acct_id,
                ba1.bill_acct_id parent_bill_acct_id,
                AB.DUE_DATE,
                PG.CMPG_ID,
                ABR.NET_AMT,
                AB.DUE_AMT,
                P.PROD_NUM,
                pds.DST_ID,
                ABR.DESCR,
                p.intl_prod_id
           FROM apld_bill_rt abr,
                acct_bill ab,
                prod p,
                FCBSADM.PROD_DST pds,
                bill_acct_prod bap,
                bill_acct ba1,
                bill_acct ba2,
                prod_cmpg pg
          WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
                AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
                AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
                AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
                AND bap.intl_prod_id = abr.intl_prod_id
                AND ABR.CHRG_TP = 'INSTALLMENT'
                AND bap.intl_prod_id = pds.intl_prod_id
                AND bap.intl_prod_id = p.intl_prod_id
                AND p.intl_prod_id = pg.intl_prod_id(+)
                AND ABR.intl_prod_id = l_prod_ids(indx)
UNION
    SELECT AB.ACCT_BILL_ID,
                AB.BILL_NO,
                AB.INV_ID,
                AB.BILL_DATE,
                ba1.bill_acct_id,
                ba1.bill_acct_id parent_bill_acct_id,
                AB.DUE_DATE,
                PG.CMPG_ID,
                ABR.NET_AMT,
                AB.DUE_AMT,
                P.PROD_NUM,
                pds.DST_ID,
                ABR.DESCR,
                p.intl_prod_id
           FROM apld_bill_rt abr,
                acct_bill ab,
                prod p,
                FCBSADM.PROD_DST pds,
                bill_acct_prod bap,
                bill_acct ba1,
                prod_cmpg pg
          WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
                AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
                --AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
                AND ba1.intl_bill_acct_id = bap.intl_bill_acct_id
                AND bap.intl_prod_id = abr.intl_prod_id
                AND ABR.CHRG_TP = 'INSTALLMENT'
                AND bap.intl_prod_id = pds.intl_prod_id
                AND bap.intl_prod_id = p.intl_prod_id
                AND p.intl_prod_id = pg.intl_prod_id(+)
                AND ABR.intl_prod_id = l_prod_ids(indx);

      v_cnt := v_cnt + 1;

      IF MOD (v_cnt, 10000) = 0
      THEN
         COMMIT;
      END IF;
    COMMIT;  
    
    
    END LOOP;
   CLOSE c1;
end;

Your procedure treats everything, it just works in bulks of 10000 records, thus prone to parallelism.您的程序处理一切,它只适用于 10000 条记录的批量,因此容易出现并行性。

There is a loop in the forall, the insert will be executed for all the records (10K) forall中有一个循环,insert会针对所有记录(10K)执行

Regarding the v_cnt mod, you can remove it (but not advised to) with no issues other than performances, the original author most likely found that the redo segments might get really big, so he's just commiting everywhile and so (but since he truncates the table in the beginning, this isn't an issue at all).关于 v_cnt mod,你可以删除它(但不建议这样做)除了性能之外没有任何问题,原作者很可能发现重做段可能会变得非常大,所以他只是每次都提交等等(但因为他截断了表,这根本不是问题)。

You don't need to do any bulk collect in that procedure.您不需要在该过程中执行任何bulk collect It is non sense.这是没有意义的。 Why?为什么? Because you are not collecting values in the type and applying logic over them, you just get the distinct intl_prod_id in a cursor and make a select for each one, something you can easily solve with a CTE expression.因为您没有收集类型中的值并对其应用逻辑,所以您只需在distinct intl_prod_id的 intl_prod_id 并为每个值创建一个 select,您可以使用 CTE 表达式轻松解决这些问题。

If you use also direct path, by applying the hint append , then you will get a much better procedure and huge boost in performance.如果您还使用直接路径,通过应用提示append ,那么您将获得更好的过程和性能的巨大提升。

Keep in mind that for each row in the cursor, you need to run the insert/select, that implies to join all the tables involved in the operation for each value in the cursor. Try to apply the principle, the easier the better.请记住,对于cursor中的每一行,您都需要运行insert/select,这意味着对cursor中的每个值连接所有参与操作的表。尝试应用原则,越简单越好。

create or replace procedure GPU_DATA_EXTRACTOR_TEST(pid_billdate DATE) is

begin
    execute immediate 'truncate table GPU_INV_TEST';

   INSERT /*+append */ INTO GPU_INV_TEST
   with x as 
   (  SELECT /*+materialize */ DISTINCT intl_prod_id as intl_prod_id 
      FROM apld_bill_rt abr,
           acct_bill ab
      WHERE abr.CHRG_TP = 'INSTALLMENT'
          AND abr.TAX_CATG_ID = 'NOTAX'
          AND abr.acct_bill_id = ab.acct_bill_id
          AND ab.bill_date = pid_billdate 
    )
      SELECT AB.ACCT_BILL_ID,
                AB.BILL_NO,
                AB.INV_ID,
                AB.BILL_DATE,
                ba2.bill_acct_id,
                ba1.bill_acct_id parent_bill_acct_id,
                AB.DUE_DATE,
                PG.CMPG_ID,
                ABR.NET_AMT,
                AB.DUE_AMT,
                P.PROD_NUM,
                pds.DST_ID,
                ABR.DESCR,
                p.intl_prod_id
           FROM apld_bill_rt abr,
                acct_bill ab,
                prod p,
                FCBSADM.PROD_DST pds,
                bill_acct_prod bap,
                bill_acct ba1,
                bill_acct ba2,
                prod_cmpg pg , 
                x
          WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
                AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
                AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
                AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
                AND bap.intl_prod_id = abr.intl_prod_id
                AND ABR.CHRG_TP = 'INSTALLMENT'
                AND bap.intl_prod_id = pds.intl_prod_id
                AND bap.intl_prod_id = p.intl_prod_id
                AND p.intl_prod_id = pg.intl_prod_id(+)
                AND ABR.intl_prod_id = x.intl_prod_id
    UNION
    SELECT AB.ACCT_BILL_ID,
                AB.BILL_NO,
                AB.INV_ID,
                AB.BILL_DATE,
                ba1.bill_acct_id,
                ba1.bill_acct_id parent_bill_acct_id,
                AB.DUE_DATE,
                PG.CMPG_ID,
                ABR.NET_AMT,
                AB.DUE_AMT,
                P.PROD_NUM,
                pds.DST_ID,
                ABR.DESCR,
                p.intl_prod_id
           FROM apld_bill_rt abr,
                acct_bill ab,
                prod p,
                FCBSADM.PROD_DST pds,
                bill_acct_prod bap,
                bill_acct ba1,
                prod_cmpg pg, 
                x
          WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
                AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
                --AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
                AND ba1.intl_bill_acct_id = bap.intl_bill_acct_id
                AND bap.intl_prod_id = abr.intl_prod_id
                AND ABR.CHRG_TP = 'INSTALLMENT'
                AND bap.intl_prod_id = pds.intl_prod_id
                AND bap.intl_prod_id = p.intl_prod_id
                AND p.intl_prod_id = pg.intl_prod_id(+)
                AND ABR.intl_prod_id = x.intl_prod_id;

         COMMIT;
end;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM