如何优化这个 PL/SQL 块?

How to optimize this PL/SQL block?

我需要在名为 table_to_update 的 table 中更新名为 text 的列。字段 text 是来自另一个名为 other_table 的 table 的 3 个字符串的串联。该脚本按预期工作,但问题是执行时间很长(> 20 小时),因为 table table_to_update 中大约有 2000 万个数据集需要更新。

我有什么想法可以提高这个脚本的性能吗?

DECLARE
 v_field1 VARCHAR(20);
 v_field2 VARCHAR(20);
 v_field3 VARCHAR(20);
 v_text VARCHAR(100);


BEGIN
 FOR rec IN (select t_pk from table_to_update where state = 'STATE_1' and text is null order by t_pk desc) -- 20 millions data sets
LOOP

 v_text := null;

  FOR other_record IN (select distinct field1, field1, field3 from other_table where t_fk = rec.t_pk)
  LOOP
    v_field1 := other_record.field1;
    v_field2 := other_record.field2;
    v_field3 := other_record.field3;
    v_text := v_text || v_field2 || ';' || v_field1 || ': '|| v_field3 || ' ';        
  END LOOP;   

update table_to_update set text = v_text where t_pk = rec.t_pk;

END LOOP;

COMMIT;

END;

一般来说,优化 PL/SQL 块的最佳方法是尽量减少上下文切换的次数(即从程序代码切换到 SQL 并返回的频率)。在这种情况下,您可以将此块缩减为单个语句(假设您使用的是 11g 或更高版本):

MERGE INTO table_to_update t2u
USING      (SELECT   t_fk,
                     LISTAGG (field2 || ';' || field1 || ': ' || field3, ' ')
                        WITHIN GROUP (ORDER BY field2)
                        AS agg_field
            FROM     other_table
            GROUP BY t_fk) ot
ON         (ot.t_fk = t2u.t_pk)
WHEN MATCHED THEN
   UPDATE SET
      t2u.text = ot.agg_field
      WHERE      t2u.state = 'STATE_1' AND t2u.text IS NULL
  • LISTAGG 是一个聚合函数,它连接获得的值 来自不同的行。它是在 11g 中引入的。
  • 您也可以将其作为 UPDATE,但我更喜欢 MERGE