PL/SQL 加速长函数
Posted
技术标签:
【中文标题】PL/SQL 加速长函数【英文标题】:PL/SQL Speeding up long function 【发布时间】:2018-07-09 20:53:06 【问题描述】:我希望加快以下 PL/SQL 函数的速度。现在它已经运行了2个多小时,没有完成的迹象。我们中止了那个,并在 EXIT WHEN 为 20 时再次尝试它,但它仍然没有显示实际完成的迹象。
我们通过 SQLDeveloper 17.3 运行这些,每个 (4) 表有大约 15k 行。
我们的目标是获取我们数据库中的所有 SSN,并将第一个字符更改为非法字符,将最后两个字符更改为随机的 A-Z 组合。然后,我们必须在使用它的每个表中更新该 SSN (4)。
declare
v_random varchar2(2);
v_origin_ssn varchar2(100);
v_working_start varchar2(100);
v_working_middle varchar2(100);
v_new_ssn varchar2(100);
begin
for o in (
select distinct ssn --loop all rows in tbl_customer
from program_one.tbl_customer
)
loop
if regexp_like(o.ssn, '^[A-Za-z9].*[A-Z]$') then continue; --if this is already scrambled, skip
else
select dbms_random.string('U', 2) --create random 2 cap letters
into v_random
from dual;
v_origin_ssn := o.ssn; --set origin ssn with the existing ssn
if regexp_like(o.ssn, '^[A-Za-z]') --if first char is already alpha, leave it alone, otherwise 9
then v_working_start := substr(o.ssn, 1, 1);
else v_working_start := 9;
end if;
v_working_middle := substr(o.ssn, 2, 6); --set middle ssn with the unchanged numbers
v_new_ssn := v_working_start||v_working_middle||v_random; --create new sanitized ssn
update program_one.tbl_customer --update if exists in tbl_customer
set ssn = v_new_ssn
where ssn = v_origin_ssn;
commit;
update program_one.tbl_mhc_backup --update if exists ssn tbl_mhc_backup
set ssn = v_new_ssn
where ssn = v_origin_ssn;
commit;
update program_two.tbl_waiver --update if exists ssn tbl_waiver
set ssn = v_new_ssn
where ssn = v_origin_ssn;
commit;
update program_two.tbl_pers --update if exists in tbl_pers
set ssan = v_new_ssn
where ssan = v_origin_ssn;
commit;
end if;
--dbms_output.put_line(v_origin_ssn||' : '||v_new_ssn); --output test string to verify working correctly
end loop;
end;
【问题讨论】:
三个是您进行逐行更新的原因吗?还是经常犯?更新是否会被另一个会话中未提交的更改阻止? 执行期间会话在等待什么? 如果我是你,我会创建一个新表来保存旧值和新值(你应该能够通过单个insert into ... select ...
语句填充),然后你可以使用使用更新或(更有可能)合并语句来更新其他表中的值。批量执行应该比您的逐行(又名逐个慢)方法快得多。
@alexpoole 我们运行它的开发服务器在我们的测试期间不可用,因此不应该有任何竞争性更改。当我们今天离开时,我们让它每 20 次循环而不是每次更新后提交。
@bonist:我支持你的建议并写了一些示例代码。 Daminta:为了您的站立:建议先在真人大小的副本上进行测试运行以获得时间。我相信它会非常快。也许在单独的模式中进行,也许涉及 DBA。无论如何,这是正确的、行业标准的做法。
【参考方案1】:
我会在没有纯 SQL 的函数的情况下这样做:
用新旧 ssn 创建一个表:
CREATE TABLE tmp_ssn AS
SELECT ssn, '9'||substr(ssn,2,6)||dbms_random.string('U',2) as new_ssn
FROM (SELECT distinct ssn FROM program_one.tbl_customer);
CREATE UNIQUE INDEX ui_tmp_ssn ON tmp_ssn(ssn, new_ssn);
EXEC DBMS_STATS.GATHER_TABLE_STATS(null,'tmp_ssn');
...然后一一更新表格:
MERGE INTO program_one.tbl_customer z USING tmp_ssn q ON (z.ssn=q.ssn)
WHEN MATCHED THEN UPDATE z.ssn = q.new_ssn;
COMMIT;
MERGE INTO program_one.tbl_mhc_backup z USING tmp_ssn q ON (z.ssn=q.ssn)
WHEN MATCHED THEN UPDATE z.ssn = q.new_ssn;
COMMIT;
etc
如果这仍然很慢,我会这样做
RENAME tbl_customer to tbl_customer_old;
CREATE TABLE tbl_customer as
SELECT s.new_ssn as ssn, t.col1, t.col2, ... , t.coln
FROM tbl_customer_old t JOIN tmp_ssn s USING(ssn);
DROP TABLE tbl_customer_old;
【讨论】:
到目前为止,这基本上是我们使用的方法。在我们最慢的开发服务器上,每张桌子运行大约 180 秒。我们仍然将它作为一个函数运行,但是创建临时表以首先插入然后运行合并非常快。我会等到明天再接受答案。以上是关于PL/SQL 加速长函数的主要内容,如果未能解决你的问题,请参考以下文章