有没有更快的方法在 oracle pl/sql 中每周对 120k 条记录执行合并?

Posted

技术标签:

【中文标题】有没有更快的方法在 oracle pl/sql 中每周对 120k 条记录执行合并?【英文标题】:Is there any faster way to perform merge on 120k records weekly in oracle pl/sql? 【发布时间】:2020-04-17 19:57:48 【问题描述】:

数据库中有大约 120k 条记录,我根据几个函数计算所有记录的分数,每周我必须用新记录和相应的分数更新表。

下面是我用来将数据合并到表中的过程:

create or replace procedure scorecalc
AS
score1 number;
score2 number;
score3 number;
CURSOR cur IS
 SELECT Id_number from tableA;

        r_num cur%ROWTYPE;
BEGIN
  --OPEN cur;
  FOR r_num IN cur
  LOOP
    select functionA(r_num.id_number),functionb(r_num.id_number),functionc(r_num.id_number)  into score1, score2,score3 from dual;
Merge into scores A USING
(Select
 r_num.id_number as ID, score1 as scorea, score2 as scoreb, score3 as scorec, TO_DATE(sysdate, 'DD/MM/YYYY') as scoredate
FROM DUAL) B
ON ( A.ID = B.ID and A.scoredate = B.scoredate)
WHEN NOT MATCHED THEN
INSERT (
 ID, scorea, scoreb, scorec, scoredate)
VALUES (
 B.ID, B.scorea, B.scoreb, B.scorec,B.scoredate)
WHEN MATCHED THEN
UPDATE SET
 A.scorea = B.scorea,
 A.scoreb = B.scoreb,
 A.scorec = B.scorec;
 COMMIT;
  END LOOP;
END;

而functionA/B/C有复杂的查询,加入其中计算分数。

请建议我任何提高性能的方法,因为目前使用这个 sn-p 代码我只能在 1 小时内插入一些 2k 记录?我可以在这里使用并行 DML 吗? 谢谢!

【问题讨论】:

【参考方案1】:

为什么要在程序中这样做?这一切都可以通过 DML 完成:

MERGE INTO scores a USING
  (SELECT ta.id_number AS ID, 
          functionA(ta.id) AS scoreA,
          functionB(ta.id) AS scoreB,
          functionC(ta.id) AS scoreC,
          TO_DATE(sysdate, 'DD/MM/YYYY') as scoredate
   FROM tableA ta) b
ON (a.id = b.id AND a.scoredate = b.scoredate)
WHEN MATCHED THEN UPDATE SET
  a.scorea = b.scorea,
  a.scoreb = b.scoreb,
  a.scorec = b.scorec
WHEN NOT MATCHED THEN INSERT (ID, scorea, scoreb, scorec, scoredate)
VALUES (B.ID, B.scorea, B.scoreb, B.scorec,B.scoredate);

如果您想在此之后尝试使用PARALLEL 提示,请随意。但是你绝对应该摆脱那个光标并停止“慢慢地”处理。

【讨论】:

我在程序中这样做是因为我需要为每个星期天晚上安排它 @PriyadarshniSagar 如果您使用 DBMS_SCHEDULER,只需将 DML 包装在一个简单的匿名块中(只需 BEGINEND;)。您可以将其用作工作的 PL/SQL 块。【参考方案2】:

我已经取得了一些成功的东西是从一个 select 语句中插入的。它的性能非常好,因为它不涉及逐行插入。

在你的情况下,我认为它会是这样的:

INSERT INTO table (ID, scorea, scoreb, scorec, scoredate)
SELECT functionA(id_number), functionB(id_number), functionC(id_number)
FROM tableA

可以在下面的链接中找到一个示例: https://docs.oracle.com/cd/B12037_01/appdev.101/b10807/13_elems025.htm

【讨论】:

【参考方案3】:

要安排它,只需将语句 @Del 放在一个过程块中;

create or replace procedure Saturday_Night_Merge is 
begin 
    <Put the merge statement here> 
end Saturday_Night_Merge;

【讨论】:

以上是关于有没有更快的方法在 oracle pl/sql 中每周对 120k 条记录执行合并?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 Oracle 中刷新 PL/SQL 的输出?

有没有办法在 Oracle 中刷新 PL/SQL 的输出?

转:PL/SQL在 win8.1系统下连接Oracle11g没有database处理方法

Oracle PL/SQL 中的漂亮打印

Oracle PL/SQL:如何在长包中查找未使用的变量?

oracle pl/sql 将异常类型传递给函数