假设我们有两个名为Tb1和Tb2的表,我们将把数据从一个替换为另一个。 Tb1是主要的数据来源,Tb2是目的地。这种更换操作有3个部分。
在第一部分中,我们将验证Tb1中的所有行并检查它们是否正确。例如,国家安全代码必须具有10位数字,或者真正的客户必须具有有效的出生日期,因此根据这些验证规则,已经考虑了28种不同的验证方法和错误代码。 在验证过程中,每个被破坏的行的描述和状态都将更新为新状态。
第2部分修复了行的问题,第3部分将它们替换为Tb2。
例如,这一行表示它有4个不同的错误。
- Tb1.desc = 6,8,14,16
- Tb1.sts = 0
正确的数据行
- Tb1.desc = Null i - Tb1.sts = 1
我最近一直在研究第一部分,并提出了一个解决方案,它工作正常,但速度太慢。不幸的是,验证100,000行需要31分钟。在实际情况下,我们将验证超过200万条记录,因此尽管它具有所有功能,但它完全没用。
让我们来看看我的包裹:
procedure Val_primary IS
begin
Open X_CUSTOMER;
Loop
fetch X_CUSTOMER bulk collect into CUSTOMER_RECORD;
EXIT WHEN X_CUSTOMER%notfound;
For i in CUSTOMER_RECORD.first..CUSTOMER_RECORD.last loop
Val_CTYP(CUSTOMER_RECORD(i).XCUSTYP);
Val_BRNCH(CUSTOMER_RECORD(i).XBRNCH);
--Rest of the validations ...
UptDate_Val(CUSTOMER_RECORD(i).Xrownum);
end loop;
CUSTOMER_RECORD.delete;
End loop;
Close X_CUSTOMER;
end Val_primary;
验证程序内:
procedure Val_CTYP(customer_type IN number)IS
Begin
IF(customer_type<1 or customer_type>3)then
RW_FINAL_STATUS:=0;
FINAL_ERR_DSC:=Concat(FINAL_ERR_DSC,ERR_INVALID_CTYP);
End If;
End Val_CTYP;
更新程序内:
procedure UptDate_Val(rownumb IN number) IS
begin
update tb1 set tb1.xstst=RW_FINAL_STATUS,tb1.xdesc=FINAL_ERR_DSC where xc1customer.xrownum=rownumb;
RW_FINAL_STATUS:=1;
FINAL_ERR_DSC:=null;
end UptDate_Val;
有没有办法减少执行时间? 超过200万条记录必须在20分钟内完成。
答案 0 :(得分:0)
也许每个验证检查可以是内联视图中的case
表达式,您可以在封闭查询中连接它们等,为您提供一个可以驱动update
的SQL语句。有点像:
select xxx, yyy, zzz -- whatever columns you need from xc1customer
, errors -- concatenation of all error codes that apply
, case when errors is not null then 0 else 1 end as status
from ( select xxx, yyy, zzz
, trim(ltrim(val_ctyp||' ') || ltrim(val_abc||' ') || ltrim(val_xyz||' ') || etc...) as errors
from ( select c.xxx, c.yyy, c.zzz
, case when customer_type < 1 or customer_type > 3 then err_invalid_ctyp end as val_ctyp
, case ... end as val_abc
, case ... end as val_xyz
from xc1customer c
)
);
坚持程序方法,缓慢的部分似乎是单行更新。将所有2000万行批量收集到会话内存中仅用于应用2000万个单独更新没有任何优势。快速解决方法是向limit
添加bulk collect
子句(并将exit
移动到循环的底部),让您的验证过程设置一个值数组而不是更新表,并将更新批处理为每循环迭代一次forall
。
通过将记录和数组传入和传出过程而不是将所有内容都设置为全局变量,您可以更自由一点,因为通过引用传递意味着没有性能开销。
答案 1 :(得分:0)
有两种潜在的攻击线。
应用这些建议,您最终会得到一个看起来有点像这样的程序:
procedure one_and_only is
begin
open x_customer;
<< tab_loop >>
loop
fetch x_customer bulk collect into customer_record
limit 1000;
exit when customer_record.count() = 0;
<< rec_loop >>
for i in customer_record.first..customer_record.last loop
val_and_fix_ctyp(customer_record(i).xcustyp);
val_and_fix_brnch(customer_record(i).xbrnch);
--rest of the validations ...
end loop rec_loop;
-- apply the cleaned data to target table
forall j in 1..customer_record.count()
insert into table_2
values customer_record(j);
end loop tab_loop;
close x_customer;
end one_and_only;
请注意,此方法要求customer_record
集合与目标表的投影相匹配。此外,请勿使用%notfound
来测试光标的结尾,除非您可以保证读取记录的总数是LIMIT编号的精确倍数。