lundi 22 décembre 2014

Code Rewrite for the better ( SQL vs PL , Bulk )



1] Rewrite : One SQL order vs. Cursor loop

It is obvious that a single call to the RDBMS engine is better than going back and forth from the PL to the SQL engine when using cursor.
Example :


     FOR v_P1 in
     (select no_init_appel_cg,dat, plage_demi_heure, sum(duree_conversation+duree_message_usager+duree_message_accueil) as duree_relation_cso
from FACTS_4760 F where  f.sens_appel='ENTRANT'
and f.no_init_appel_cg is not null
group by no_init_appel_cg,dat, plage_demi_heure)
     LOOP
               NB := NB+1;
       update faits_v2
              set duree_relation_cso=v_P1.duree_relation_cso
       where      no_poste_callipso=v_P1.no_init_appel_cg
       and        dat=v_P1.dat
       and        plage_demi_heure=v_P1.plage_demi_heure
       and no_sda like '041331%';
       Commit;
     END LOOP;
     insert into APP_LOG(TEXT)     values('APP_RECUP_4760 : ' || v_cursor || ' Ok : '|| to_char(NB));
          commit;


Rewrite to


update faits_v2 a
set duree_relation_cso=(
select sum(duree_conversation+duree_message_usager+duree_message_accueil) as duree_relation_cso
from FACTS_4760 b where  b.sens_appel='ENTRANT' and b.no_init_appel_cg is not null
and a.no_poste_callipso=b.no_init_appel_cg and a.dat=b.dat and a.plage_demi_heure=b.plage_demi_heure
group by no_init_appel_cg,dat, plage_demi_heure
)
where no_sda like '041331%';


Multi-column example


   v_cursor:= 'P012';
   NB := 0;
-- Maj des infos Postes
     FOR v_P1 in
     (
select distinct no_poste_callipso ,
t.lib_poste,
t.dsit_nosite,
t.type_tel,
t.stat_accueil,
t.std_identifie,
decode(nvl(t.std_identifie,'Non'),'Oui','ACCUEIL','POSTE') as Niveau_Accueil,
t.mevo,
t.nb_lignes_entrantes,
t.uo_id,
p.uo_abrev,
p.uo_id_dga,
p.uo_abrev_dga,
p.uo_id_dir,
p.uo_abrev_dir,
p.uo_id_ser,
p.uo_abrev_ser
from bi_app_ods.dsit_telephonev3 t ,uo_public p
where  t.no_poste_callipso is not null
and  nvl(t.uo_id,529)=p.uo_id(+)
)
     LOOP
               NB := NB+1;

   v_cursor:= 'P012a';
       update faits_4760 set
no_poste_callipso=v_P1.no_poste_callipso,
lib_poste=v_P1.lib_poste,
dsit_nosite=v_P1.dsit_nosite,
type_tel=v_P1.type_tel,
stat_accueil=v_P1.stat_accueil,
std_identifie=v_P1.std_identifie,
Niveau_Accueil=v_P1.Niveau_Accueil,
mevo=v_P1.mevo,
nb_lignes_entrantes=v_P1.nb_lignes_entrantes,
uo_id=v_P1.uo_id,
uo_abrev=v_P1.uo_abrev,
uo_id_dga=v_P1.uo_id_dga,
uo_abrev_dga=v_P1.uo_abrev_dga,
uo_id_dir=v_P1.uo_id_dir,
uo_abrev_dir=v_P1.uo_abrev_dir,
uo_id_ser=v_P1.uo_id_ser,
uo_abrev_ser=v_P1.uo_abrev_ser 
       where   no_poste_callipso=v_P1.no_poste_callipso and lib_poste is null;


Rewrite to

   v_cursor:= 'P012a';
update faits_4760_2013_03 F
set(
lib_poste,
dsit_nosite,
type_tel,
stat_accueil,
std_identifie,
Niveau_Accueil,
mevo,
nb_lignes_entrantes,
uo_id
)=
(select 
t.lib_poste,
t.dsit_nosite,
t.type_tel,
t.stat_accueil,
t.std_identifie,
decode(nvl(t.std_identifie,'Non'),'Oui','ACCUEIL','POSTE') as Niveau_Accueil,
t.mevo,
t.nb_lignes_entrantes,
t.uo_id
from bi_app_ods.dsit_telephonev3 t
where  t.no_poste_callipso =f.no_poste_callipso
)
where no_poste_callipso is not null;
Commit;


2] Use DBMS_ERRLOG to help debugging

One drawback of the previous rewriting is that failures rollback the entire DML.
We can use the ERRLOG 10g feature to have more information about the run and errors.

-- test Update with Reject Management
drop table faits ;
drop table err$_FACTS ;

create table faits ( a int , b int , c NUMBER(7,2) , d varchar2(5) ) ;
insert into faits values ('1','1','1', 'a');
insert into faits values ('2','10','5', 'b');
insert into faits values ('3','20','15', 'c');
insert into faits values ('3','30','40', 'd');
insert into faits values ('3','30','40', 'e');
insert into faits values ('2','40','30', 'f');
alter table faits add constraint faits_check_c check(c >= 0);

exec dbms_errlog.create_error_log( 'FACTS' ) ;

select * from FACTS
A      B      C      D
1      1      1      a
2      10     5      b
3      20     15     c
3      30     40     d
3      30     40     e
2      40     30     f

update faits set c=b-c -- ora-02290 constraint violation

select * from FACTS
A      B      C      D
1      1      1      a
2      10     5      b
3      20     15     c
3      30     40     d
3      30     40     e
2      40     30     f

select * from err$_FACTS -- no rows

update faits set c=b-c LOG ERRORS ('Test Update') REJECT LIMIT UNLIMITED -- 4 rows updated out of 6

select * from FACTS -- 4 updates
A      B      C      D
1      1      0      a
2      10     5      b
3      20     5      c
3      30     40     d
3      30     40     e
2      40     10     f

select * from err$_FACTS -- 2 rows

ORA_ERR_NUMBER$ ORA_ERR_MESG$                  ORA_ERR_ROWID$       OR ORA_ERR_TAG$         A     B     C     D
--------------- ------------------------------ -------------------- -- -------------------- ----- ----- ----- -----
           2290 ORA-02290: violation de contra AAAnFHAAdAAJbkUAAD   U  Test Update          3     30    -10   d
                intes (BI_APP_DTM.FACTS_CHECK_
                C) de vérification

           2290 ORA-02290: violation de contra AAAnFHAAdAAJbkUAAE   U  Test Update          3     30    -10   e
                intes (BI_APP_DTM.FACTS_CHECK_
                C) de vérification

rollback ;

-- reject limit N : N errors BEFORE Statement fails

update faits set c=b-c LOG ERRORS ('Test Update') REJECT LIMIT 0 -- ora-02290 constraint violation, no updates

update faits set c=b-c LOG ERRORS ('Test Update') REJECT LIMIT 1 -- ora-02290 constraint violation, no updates

select * from FACTS
A      B      C      D
1      1      1      a
2      10     5      b
3      20     15     c
3      30     40     d
3      30     40     e
2      40     30     f

update faits set c=b-c LOG ERRORS ('Test Update') REJECT LIMIT 2 -- 4 rows updated