Search code examples
oracleperformanceplsqlquery-optimization

Is there a way to optimize this query?


declare
  n_docid number;
  n_orgid number;
  n_docstateid number;
  n_docstateversion number;
  n_doctypeid number;
  n_count number;
begin
  for I in (select DOCID from DC_EXP_BO where INF_DATEDOCUMENT > '01.01.17' and 
INF_DATEDOCUMENT < '31.12.17')
loop
begin
  select DOCID, DOCSTATEID, DOCTYPEID, DOCSTATE_VERSION into 
  n_docid, n_docstateid, n_doctypeid, n_docstateversion from DOC 
  where DOCID = I.DOCID;

  select ORGID into n_orgid from ORG
  where systemname = (select distinct RB_CODEGRBS from DC_EXP_BO where DOCID = n_docid);


  select count(*) into n_count from ROUTECONTEXT
  where DOCID = n_docid and ORGID = n_orgid;

  if (n_count = 0) then
  insert into ROUTECONTEXT 
    (ROUTECONTEXTID, VERSION, DOCID, LOCALDOCSTATEID, OWNERID, LASTPRINTDATE, PRINTED, RECEIVED, ORGID, ARCHIVE, EXPORTSTATUS, DOCTYPEID, DOCSTATEID, DOCSTATE_VERSION, DELETED)
  values 
    (sq_routeContext.NEXTVAL, 0, n_docid, n_docstateid, null, null, 0, 0, n_orgid, 0, 'NOT_EXPORTED', n_doctypeid, n_docstateid, n_docstateversion, 0);
  end if;
exception
  when no_data_found then
continue;
end;
end loop;
end;
/

We wrote datafix for production. And there is a problem. For statement select can return about 1 million IDs. Is it possible someway to optimize this query?


Solution

  • The most effective optimization you can make is to replace the row-by-row inserts and lookups in a loop with a single set-based operation:

    insert into ROUTECONTEXT 
        (ROUTECONTEXTID, VERSION, DOCID, LOCALDOCSTATEID, OWNERID, LASTPRINTDATE, PRINTED, RECEIVED, ORGID, ARCHIVE, EXPORTSTATUS, DOCTYPEID, DOCSTATEID, DOCSTATE_VERSION, DELETED)
    select sq_routeContext.NEXTVAL, 
              0, 
              DOC.DOCID, 
              DOC.DOCSTATEID, 
              null,
              null,
              0,
              0,
              org.ORGID,
              0,
              'NOT_EXPORTED',
              DOC.DOCSTATEID, 
              DOC.DOCTYPEID, 
              DOC.DOCSTATE_VERSION ,
              0
    from DC_EXP_BO
        join doc
            on DC_EXP_BO.DOCID = DOC.DOCID 
        join org 
            on org.systemname =  DC_EXP_BO.RB_CODEGRBS 
    where DC_EXP_BO.INF_DATEDOCUMENT > date '2017.01.01'
    and DC_EXP_BO.INF_DATEDOCUMENT < date '2017.12.31' 
    and not exists ( select null 
                     from ROUTECONTEXT
                     where ROUTECONTEXT.DOCID = doc.docid 
                     and ROUTECONTEXT.ORGID = org.orgid 
                   )
    /
    

    Assuming DC_EXP_BO.INF_DATEDOCUMENT is a DATE datatype, using proper date semantics may be more performative and will certainly be safer. But it's a string replace that bit of the WHERE clause with what you posted in your question.