Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PL/SQL脚本运行非常慢_Sql_Performance_Oracle_Plsql - Fatal编程技术网

PL/SQL脚本运行非常慢

PL/SQL脚本运行非常慢,sql,performance,oracle,plsql,Sql,Performance,Oracle,Plsql,我有一个表mytable**id**,colA,colB,有500万条记录。colA,colB没有其他限制。我必须将colB中的值复制到colA并使colB为null。下面是我创建的过程。有时运行时间为5分钟,有时运行时间为45分钟。这个脚本有什么问题?我确信在此期间没有其他进程访问此表。我如何优化它?我知道还有很多其他因素会影响这台机器的速度,比如DB引擎本身速度慢,可能是当时机器在满负荷运转。我在寻找我手中的东西,比如我的剧本 DECLARE l_update_total

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

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

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

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

UPDATE mytable
   SET colB = null,
       colA = colB
 WHERE colA IS NULL;
纯SQL解决方案将比PL/SQL解决方案更快

但是,如果您不试图理解运行时变化的原因,那么要提高性能将非常困难。如果系统负载过重,导致过程的运行时增加了40分钟,而这一切都不是由于锁定造成的,因为您声称没有其他会话正在读取或写入所讨论的表,则完全有可能在单个SQL语句的运行时增加40分钟


如果您坚持使用较慢的PL/SQL方法,至少在循环中进行提交,以避免在每个批处理中产生这种开销。

对于Jeff Moden的粉丝来说,数据库查询不是为了一行一行地执行RBAR。考虑数据集,而不是行

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

UPDATE mytable SET colB=null, colA=colB WHERE colA is null
由于您似乎确信在操作过程中没有其他进程接触此表,因此锁定不应该是一个问题。然而,现有资源很可能是在考虑记录的数量


如果在单个查询中执行操作对服务器来说太苛刻,请尝试一种混合解决方案,每次使用单个update语句更新几千行。我的PL/SQL时代已经很遥远了,从那以后有很多T-SQL,所以我现在不能给你确切的synthax,但想法仍然是一样的。

脚本的错误在于它使用了游标……使用这种格式的500万条记录,你正在运行500万次更新。SQL是一种基于集合的语言,而不是线性语言,因此一次500万行的更新速度可能比一行的500万次更新速度快500000%……您需要重写它,以便它是一个语句,而不是延迟响应的两个循环。但我真的可以这样做吗?可乐也变空了,不是吗?我会马上在一个小集合上试试。@Naresh-我发布的UPDATE语句将colA设置为colB的旧/现有值,并将colB设置为NULL。当然,除非现有colB值已经为NULL,否则您不会将colA设置为NULL。对于那些对此感到好奇的人,我如何一次更新5000行?为了做到这一点,我必须得到5000把钥匙?所以我需要另一个问题,对吗?你能给我举个例子吗?在Oracle中,与SQL Server相比,执行单个事务几乎总是比执行分块更新快。只有当其他会话想要修改值时,锁定才是一个问题。在Oracle中,读卡器从不阻止写卡器,写卡器也从不阻止读卡器。