oracle - PLSQL 中 BULK COLLECT 中的 FORALL 用法
问题描述
您好,我有一个程序和问题。此过程用于提取数据,然后将它们插入到一个表中。我意识到我们在 FORALL 语法中不使用循环。所以我的目的是提取 10.000 条记录,然后将这 10.000 条记录插入到一个表中。我想知道的是,该过程只是在插入 10.000 条记录后停止还是继续其工作?我问是因为 FORALL 内部没有循环吗?我的第二个问题是我应该删除脚本中的 v_cnt 和 IF MOD (v_cnt, 10000) = 0 行吗?
我在下面添加脚本,我愿意接受任何修复建议或其他任何事情,谢谢你。
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;
解决方案
您的程序处理所有内容,它仅适用于 10000 条记录的批量,因此容易出现并行性。
forall中有一个循环,对所有记录(10K)都会执行insert
关于 v_cnt mod,您可以删除它(但不建议这样做),除了性能之外没有其他问题,原作者很可能发现重做段可能会变得非常大,所以他只是随时提交等等(但因为他截断了表,这根本不是问题)。
推荐阅读
- xml - 如何从 kotlin 为布局分配背景
- visual-studio-code - 使用浏览器同步证书时 Excel 插件无法以 SSL 启动
- unix - iconv 从 UTF-16BE 到 UTF-8 转换为类似中文的字符
- excel - 使用 Excel VBA 发送邮件时,Outlook 有时会崩溃
- clipboard - 从剪贴板设置和获取对象
- amazon-web-services - AWS Elasticache CPU 利用率因阅读器而异
- arrays - 如何在 Windows 上查找获取用户的桌面地址?
- typescript - 如何使用 Protobuf 生成的类作为 TypeScript 的类型?
- python - 真不等于负<0
- ios - SwiftUI - 太多预览