0

我们正在从全局临时表中迭代 100k+ 条记录。下面的存储过程将一一迭代全球临时表中的所有记录,并且必须处理以下三个步骤。

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

因此,每条记录都必须处理这 3 个步骤,最终的文档名称将存储在表中以供成功记录。如果任何步骤中出现任何错误,则将为该记录存储错误消息。

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

  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;
4

1 回答 1

1

您有许多潜在的性能影响。这是一个:

“我们正在从全局临时表中迭代 100k+ 条记录”

全局临时表可能非常慢。填充它们意味着将所有数据写入磁盘;从它们读取意味着从磁盘读取。这是可以避免的大量 I/O。此外,GTT 使用临时表空间,因此您可能会与其他执行大型排序的会话发生争用。

这是另一个危险信号:

FOR R1 IN C1 LOOP
... FOR R2 IN C2(R1.ISBN) LOOP

SQL 是一种基于集合的语言。它针对以高性能方式连接表和返回数据集进行了优化。嵌套游标循环意味着逐行处理,这无疑更容易编码,但可能比等效的集合操作慢几个数量级。

--To check whether Product is exists or not

您有几个从同一个表中选择的查询(AN“ANP ) using the same criteria (isbn”)。也许所有这些重复是验证您的业务规则的唯一方法,但似乎不太可能。

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

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

UPDATE GT_ADD_ISBNS

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

“有没有办法通过批处理来使存储过程本身的这个过程更快?”

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

需要考虑的事项:

  1. 用您用来填充临时表的查询替换对临时表的写入和读取
  2. 重写循环以使用具有高 LIMIT(例如 1000)的 BULK COLLECT 来提高选择效率。了解更多
  3. 填充数组并使用 FORALL 来提高更新效率。了解更多
  4. 尝试通过将逻辑合并到主查询中来删除所有这些单独的查找,使用 OUTER JOIN 语法来测试是否存在。

这些都是猜测。如果您真的想知道程序将时间花在哪里——而这种知识是所有成功调优的根源,所以您应该想知道——您应该在 PL/SQL Profiler 下运行该程序。这将告诉您哪些线路花费的时间最多,而这些线路通常是您需要集中精力进行调整的线路。如果您还没有访问 DBMS_PROFILER 的权限,您将需要一个 DBA 来为您运行安装脚本。了解更多

“我们可以把这段代码改成 Java 并在多线程模式下运行这段代码吗?”

鉴于减慢过程的原因之一是从临时表中选择的 I/O 成本,因此多线程很有可能会引入进一步的争用,实际上会使事情变得更糟。您应该首先寻求改进存储过程。

于 2018-02-20T08:06:46.180 回答