如何 运行 批处理模式下的存储过程或 运行 并行处理中的存储过程

how to run the stored procedure in batch mode or in run it in parallel processing

我们正在迭代来自全局临时 table.below 的 100k+ 条记录,存储过程将逐条迭代来自全局临时 table 的所有记录,并且必须处理以下三个步骤。

  1. 查看产品是否存在
  2. 查看资产中的产品是否有'category'。
  3. 查看资产的文件名是否以“%pdf%”开头。

所以每条记录都要经过这3个步骤,最终的文件名会被存储在table中,才算成功记录。如果任何步骤中出现任何错误,则会为该记录存储错误消息。

以下存储过程需要很长时间才能处理,因为它是按顺序处理的。

  1. 有没有办法通过批处理使存储过程本身的这个过程更快?
  2. 如果在存储过程中不可行,那么我们可以将这段代码改为Java和运行多线程模式下的这段代码吗?比如创建 10 个线程,每个线程将同时获取一条记录并处理这段代码。如果有人提供一些伪代码,我会很高兴。

建议使用哪种方法?

DECLARE
V_NODE_ID  VARCHAR2(20);
V_FILENAME VARCHAR2(100);
V_CATEGORY_COUNT INTEGER :=0;  
FINAL_FILNAME VARCHAR2(2000);
V_FINAL_ERRORMESSAGE VARCHAR2(2000);


CURSOR C1 IS
SELECT isbn FROM GT_ADD_ISBNS GT;

CURSOR C2(v_isbn in varchar2) IS
SELECT ANP.NODE_ID NODE_ID
        FROM 
        table1 ANP,
        table2 ANPP,
        table3 AN
        WHERE 
      ANP.NODE_ID=AN.ID AND
    ANPP.NODE_ID=ANP.NODE_ID AND
    AN.NAME_ID =26 AND
    ANP.CATEORGY='category' AND
    ANP.QNAME_ID='categories'  AND
        ANP.NODE_ID IN(SELECT CHILD_NODE_ID 
                  FROM TABLE_ASSOC START WITH PARENT_NODE_ID IN(v_isbn) 
                      CONNECT BY PRIOR CHILD_NODE_ID = PARENT_NODE_ID);


BEGIN
--Iterating all Products
FOR R1 IN C1 
LOOP

FINAL_FILNAME :='';
BEGIN


--To check whether Product is exists or not
SELECT AN.ID INTO V_NODE_ID 
FROM TABLE1 AN,
TABLE2 ANP
WHERE
AN.ID=ANP.NODE_ID AND
ANP.VALUE in(R1.ISBN);


V_CATEGORY_COUNT :=0;
V_FINAL_ERRORMESSAGE :='';

--To check Whether Product inside the assets are having the 'category' is applied or not
FOR R2 IN C2(R1.ISBN) 
LOOP

V_CATEGORY_COUNT := V_CATEGORY_COUNT+1;  

BEGIN
--In this Logic Product inside the assets have applied the 'category' But those assets are having documents LIKE '%pdf%' or not
SELECT ANP.STRING_VALUE  into V_FILENAME
        FROM 
        table1 ANP,
        table2 ANPP,
        table3 ACD
        WHERE 
       ANP.QNAME_ID=21  AND 
       ACD.ID=ANPP.LONG_VALUE 
       ANP.NODE_ID=ANPP.NODE_ID AND
       ANPP.QNAME_ID=36 AND
       ANP.STRING_VALUE LIKE '%pdf%'  AND 
       ANP.NODE_ID=R2.NODE_ID; 

    FINAL_FILNAME := FINAL_FILNAME  || V_FILENAME ||',';

   EXCEPTION WHEN
     NO_DATA_FOUND THEN
     V_FINAL_ERRORMESSAGE:=V_FINAL_ERRORMESSAGE|| 'Category is applied for this Product But for the asset:'||  R2.NODE_ID || ':Documents[LIKE %pdf%] were not found ;';
     UPDATE GT_ADD_ISBNS SET ERROR_MESSAGE=  V_FINAL_ERRORMESSAGE  WHERE ISBN= R1.ISBN;


     END;--Iterating for each NODEID

END LOOP;--Iterating the assets[Nodes] for each product of catgeory

  --  DBMS_OUTPUT.PUT_LINE('R1.ISBN:' || R1.ISBN ||'::V_CATEGORY_COUNT:' || V_CATEGORY_COUNT);

 IF(V_CATEGORY_COUNT  = 0) THEN
     UPDATE GT_ADD_ISBNS SET ERROR_MESSAGE=  'Category is not applied to none of the Assets for this Product'  WHERE ISBN= R1.ISBN;
   END IF;  


EXCEPTION WHEN
NO_DATA_FOUND THEN
      UPDATE GT_ADD_ISBNS SET ERROR_MESSAGE=   'Product is not Found:' WHERE ISBN= R1.ISBN;
END;

  -- DBMS_OUTPUT.PUT_LINE( R1.ISBN || 'Final documents:'||FINAL_FILNAME);
      UPDATE GT_ADD_ISBNS SET FILENAME=FINAL_FILNAME WHERE ISBN= R1.ISBN;

COMMIT;
END LOOP;--looping gt_isbns
END;

您有许多潜在的性能问题。这是一个:

"We are iterating 100k+ records from global temporary table"

全局临时 tables 可能会很慢。填充它们意味着将所有数据写入磁盘;从他们那里读取意味着从磁盘读取。很多 I/O 可能是可以避免的。此外,GTT 使用 临时 table空间,因此您可能会与其他进行大量排序的会话争用。

这是另一个危险信号:

FOR R1 IN C1 LOOP<br> ... FOR R2 IN C2(R1.ISBN) LOOP

SQL 是一种 set-based 语言。它针对加入 table 和以 highly-performative 方式返回数据集进行了优化。嵌套游标循环意味着 row-by-row 处理,这无疑更容易编码,但可能比等效的集合操作慢几个数量级。

--To check whether Product is exists or not

您有多个查询 select 来自同一个 tables (AN, 'ANP) using the same criteria (isbn`)。也许所有这些重复项是验证您的业务规则的唯一方法,但这似乎不太可能。

FINAL_FILNAME := FINAL_FILNAME || V_FILENAME ||',';

也许您可以重写查询以使用 listagg() 而不是使用过程逻辑来连接字符串?

UPDATE GT_ADD_ISBNS

同样,您所有的更新都是单行操作而不是集合操作。

"Is there any way to make this process faster in the stored procedure itself by doing batch process?"

在不了解您的规则和上下文的情况下,我们无法为您重写您的逻辑,但是 15-16 小时对于此来说太长了,因此您绝对可以减少经过的时间。

需要考虑的事项:

  1. 用您用来填充它的查询替换对临时文件 table 的写入和读取
  2. 重写循环以使用具有高 LIMIT(例如 1000)的 BULK COLLECT 来提高 select 效率。 Find out more.
  3. 填充数组并使用 FORALL 提高更新效率。 Find out more.
  4. 通过将逻辑合并到主查询中,使用 OUTER JOIN 语法测试是否存在,尝试删除所有这些个体 look-ups。

这些都是猜测。如果你真的想知道程序把时间花在哪里了——而这些知识是所有成功调整的基础,所以你应该想知道——你应该 运行 PL/SQL Profiler 下的程序.这将告诉您哪些线路花费的时间最多,而这些线路通常是您需要集中精力调整的地方。如果您还没有访问 DBMS_PROFILER 的权限,则需要 DBA 为您 运行 安装脚本。 Find out more.

" can we change this code into Java and run this code in multi threaded mode?"

考虑到减慢程序的原因之一是 I/O 从临时 selecting 的成本 table 很有可能 multi-threading 可能引入进一步的争论实际上让事情变得更糟。您应该首先寻求改进存储过程。