PL / SQL脚本运行速度很慢

时间:2013-10-11 18:24:22

标签: sql performance oracle plsql

我有一张包含500万条记录的表mytable(**id**,colA,colB)。 colA,colB没有其他限制。我必须将colB中的值复制到colA并使colB为null。这是我在下面创建的程序。有时它会在5分钟内运行,有时需要45分钟。这个脚本有什么问题?我确信在此期间没有其他进程访问此表。我该如何优化? (我知道会有很多其他因素会影响速度,就像数据库引擎本身运行速度慢,可能就是机器当时正在满负荷运行。我正在寻找我手中的东西,即我的脚本。 )

 DECLARE


      l_update_total pls_integer := 0;

      CURSOR cur IS SELECT id, colB FROM mytable where colA is null;
      TYPE t_recs IS TABLE OF cur%ROWTYPE;
      l_loop_count pls_integer := 0;
      l_recs t_recs;
      l_rec cur%ROWTYPE;


    BEGIN

       OPEN cur;
       LOOP

            FETCH cur BULK COLLECT INTO l_recs LIMIT 500;

            EXIT WHEN l_recs.COUNT = 0;

            FOR indx IN 1 .. l_recs.COUNT 
            LOOP

                l_rec := l_recs(indx);
                UPDATE mytable SET colB=null,colA = l_rec.colB WHERE id = l_rec.id;
                l_update_total := l_update_total + SQL%ROWCOUNT;


            END LOOP;

            COMMIT;

       END LOOP;

END;
/

3 个答案:

答案 0 :(得分:4)

转储游标和过程逻辑,并将其重写为SQL。

答案 1 :(得分:4)

为什么不编写简单的SQL语句

UPDATE mytable
   SET colB = null,
       colA = colB
 WHERE colA IS NULL;

纯SQL解决方案将比PL / SQL解决方案更快。

但是,如果您不想了解运行时间变化的原因,那么提高性能将会非常困难。如果系统如此重载,它会为您的过程的运行时增加40分钟,而这些都不是由于锁定(因为您声称没有其他会话正在读取或写入相关表),所以完全有可能它将为单个SQL语句的运行时添加40分钟。

如果你坚持使用较慢的PL / SQL方法,至少取出循环中的commit以避免每批产生这种开销。

答案 2 :(得分:1)

数据库查询并不意味着逐行进行(RBAR,对于Jeff Moden粉丝)。考虑一组数据,而不是行。

从技术上讲,简单的更新会更好:

UPDATE mytable SET colB=null, colA=colB WHERE colA is null

由于您似乎确信在操作期间没有其他进程正在触及此表,因此锁定不应成为问题。但是,可用资源很可能是(考虑到记录的数量)。

如果在单个查询中执行操作在服务器上过于苛刻,请尝试使用混合解决方案,每次更新几千行,每次使用一个UPDATE语句。我的PL / SQL日子很远,从那时起就有很多T-SQL,所以我现在无法给你精确的合成器,但这个想法仍然是一样的。