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
Oracle PL SQL查询执行时间太长_Oracle_Performance_Plsql - Fatal编程技术网

Oracle PL SQL查询执行时间太长

Oracle PL SQL查询执行时间太长,oracle,performance,plsql,Oracle,Performance,Plsql,Person表在Finance和HR模式中分别有200万行和300万行。现在,我将用人力资源模式中的Person_状态更新财务模式中的Person status。查询在M3000服务器上运行,该服务器具有32 GB RAM,并带有Solaris 10和Oracle 11.2.2。这花了117个小时,而且还在运行。如何优化此查询。我已经在人名上创建了索引 DECLARE CURSOR c IS SELECT p1.person_no AS "PersonNo1"

Person表在Finance和HR模式中分别有200万行和300万行。现在,我将用人力资源模式中的Person_状态更新财务模式中的Person status。查询在M3000服务器上运行,该服务器具有32 GB RAM,并带有Solaris 10和Oracle 11.2.2。这花了117个小时,而且还在运行。如何优化此查询。我已经在人名上创建了索引

DECLARE
  CURSOR c IS  
    SELECT p1.person_no     AS "PersonNo1"
         , p2.person_no     AS "PersonNo2"
         , p2.person_status AS "P2_PERSON_STATUS"
      FROM person    p1
         , hr.person p2    
     WHERE (lower(p1.person_no) = lower(p2.person_no)           
           OR substr(p1.person_no, instr(p1.person_no, '-') + 1, length(p1.person_no))
              = substr(p2.person_no, instr(p2.person_no, '-') + 1, length(p2.person_no)));
BEGIN

  FOR i IN c LOOP  
    UPDATE person    
       SET person_status_id = decode(lower(i.P2_PERSON_STATUS), 'y', 1, 'n', 2)    
     WHERE (lower(person_no) = lower(i.PersonNo2)           
        OR substr(person_no, instr(person_no, '-') + 1, length(person_no))
           = substr(i.PersonNo2, instr(i.PersonNo2, '-') + 1, length(i.PersonNo2)));  
    COMMIT;  
  END LOOP;

END;
/

你可以做一些事情来优化它。查看查询计划会很有帮助

您可以使用merge语句。然后您只有一条语句,可以对该语句进行优化。像这样的

merge into person 
using hr.person person_hr 
on (person.person_no=person_hr.person_no) 
when matched then 
update set person_status_id=decode(lower(person_status),'y',1,'n',2);
您必须调整部件上的
,以匹配您的
where
语句

这可能是最佳优化的来源。也许你必须为lower和substr创建一个索引

差不多

CREATE INDEX person_idx
 ON person (lower(person_no))

当然还有子字符串等。希望这有帮助。

在作为问题提供的代码中,我可以看到有两个方面

1) Query Optimization
2) ROW BY ROW Update --> Never Recommended for such a huge records count..

Approach to Optmization.

1) Use Merge Statement as it will Bundle up the block into pure SQL thus will enhance your query.

2) Use Function based Index as i can see there are lot of functions like "LOWER" is used in the query "WHERE" conditions.
NOTE : [Over INDEXING may also cause deterioration in the performance}

3) Last but not the least if you have to go by Anonymous block only then avoid using ROW BY ROW Update. Try using Bulk collect Options as illustrated below.
Since i do not have workstation handy with me please bear with any Syntax Errors.
Let me know if this helps.

DECLARE
  TYPE p1
IS
  TABLE OF <table_name>.<COLUMN_NAME>%TYPE;
  PersonNo1 p1;
TYPE p2
IS
  TABLE OF <table_name>.<COLUMN_NAME>%TYPE;
  PersonNo2 p2;
TYPE status
IS
  TABLE OF <table_name>.<COLUMN_NAME>%TYPE;
  P2_PERSON_STATUS status;
BEGIN
  SELECT p1.person_no AS "PersonNo1" ,
    p2.person_no      AS "PersonNo2" ,
    p2.person_status  AS "P2_PERSON_STATUS" BULK COLLECT
  INTO PersonNo1,
    PersonNo2,
    P2_PERSON_STATUS
  FROM person p1 ,
    hr.person p2
  WHERE (lower(p1.person_no)                                                  = lower(p2.person_no)
  OR SUBSTR(p1.person_no, instr(p1.person_no, '-') + 1, LENGTH(p1.person_no)) = SUBSTR(p2.person_no, instr(p2.person_no, '-') + 1, LENGTH(p2.person_no)));
  FORALL I                                        IN PersonNo1.FIRST..PersonNo1.LAST
  UPDATE person
  SET person_status_id                                               = DECODE(lower(P2_PERSON_STATUS(I)), 'y', 1, 'n', 2)
  WHERE (lower(person_no)                                            = lower(PersonNo2(I))
  OR SUBSTR(person_no, instr(person_no, '-') + 1, LENGTH(person_no)) = SUBSTR(PersonNo2(I), instr(PersonNo2(I), '-') + 1, LENGTH(PersonNo2(I))));

COMMIT;

END;
1)查询优化
2) 逐行更新-->对于如此庞大的记录计数,不建议使用。。
优化方法。
1) 使用Merge语句,因为它会将块绑定到纯SQL中,从而增强您的查询。
2) 使用基于函数的索引,因为我可以看到在查询“WHERE”条件中使用了很多函数,如“LOWER”。
注意:[过度索引也可能导致性能下降}
3) 最后但并非最不重要的一点是,如果必须仅使用匿名块,则应避免使用逐行更新。请尝试使用批量收集选项,如下所示。
由于我手头没有工作站,请容忍任何语法错误。
让我知道这是否有帮助。
声明
p1型
是
类型的表格;
人1 p1;
p2型
是
类型的表格;
人2 p2;
类型状态
是
类型的表格;
P2_人员_状态;
开始
选择p1.person_no作为“PersonNo1”,
p2.人员编号为“人员2”,
p2.人员状态为“p2人员状态”批量收集
成为一号人物,
第二个人,
P2\u人员\u状态
从人p1,
人力资源部人员p2
式中(较低(p1.人员编号)=较低(p2.人员编号)
或子项(p1.人员编号,仪表(p1.人员编号,'-')+1,长度(p1.人员编号))=子项(p2.人员编号,仪表(p2.人员编号,'-')+1,长度(p2.人员编号));
所有的我都是第一个人最后一个人
更新人
设置人员状态\u id=解码(较低(P2人员状态(I)),'y',1',n',2)
式中(较低者(人数)=较低者(人数2(I))
或子项(人员编号,仪表(人员编号,“-”)+1,长度(人员编号))=子项(人员编号2(I),仪表(人员编号2(I),“-”)+1,长度(人员编号2(I));
犯罪
结束;

首先,您没有
i.person\u no
列。在光标中只有
PersonNo1
p2
列。其次,您已经选中了
substr(p1.person\u no,instr(..
在光标中,为什么要在更新中第二次这样做?这是
person\u no
列的类型?您可以执行查询计划吗?为了确保您正在读取您创建的索引,person\u no上的索引无法使用,因为此列上的
lower
substr
函数阻止了这一点。此更新可以通过一个简单的update语句完成。不需要pl/sql。在for循环中,您可以按照光标已选择的方式更新整个表。这没有意义。1.您实际上可以使用一个简单的
update
语句(无需使用pl/sql和所有循环).2.若要在表上使用索引,您可以尝试创建,另请参阅。我将合并上述建议,并向您更新查询性能。我已终止上次查询的会话,并按建议修改了查询。创建了基于函数的索引。目标架构中有重复行,因此我得到了ORA-30926:无法获得稳定集源表中的行数。我按照中的建议从目标架构中删除了重复行,但仍为ORA-30926。任务仍处于挂起状态。