A volta capita che una procedura PL\SQL sia lenta.
In questi casi per individuare le porzioni di codice lento è utile misurarne il tempo di esecuzione.
Per far ciò ho realizzato un package che implementa un cronografo.
CREATE OR REPLACE PACKAGE CRONO IS TYPE tTimer IS RECORD( s TIMESTAMP ,e TIMESTAMP ); FUNCTION new RETURN tTimer; PROCEDURE stop (this IN OUT NOCOPY tTimer); PROCEDURE reset (this IN OUT NOCOPY tTimer); FUNCTION time (this IN OUT NOCOPY tTimer) RETURN VARCHAR2; FUNCTION hour (this IN OUT NOCOPY tTimer) RETURN NUMBER; FUNCTION minute (this IN OUT NOCOPY tTimer) RETURN NUMBER; FUNCTION second (this IN OUT NOCOPY tTimer) RETURN NUMBER; END;
CREATE OR REPLACE PACKAGE BODY CRONO IS FUNCTION new RETURN tTimer IS this tTimer := NULL; BEGIN this.s := SYSTIMESTAMP; this.e := NULL; RETURN this; END; PROCEDURE starting(this IN OUT NOCOPY tTimer)IS BEGIN this.s := SYSTIMESTAMP; END; PROCEDURE stop (this IN OUT NOCOPY tTimer) IS BEGIN this.e := SYSTIMESTAMP; END; PROCEDURE reset (this IN OUT NOCOPY tTimer) IS BEGIN this.s := SYSTIMESTAMP; this.e := NULL; END; FUNCTION time (this IN OUT NOCOPY tTimer) RETURN VARCHAR2 IS ret VARCHAR2(32767):=NULL; BEGIN ret := this.e - this.s; ret := ret || ' ' || 'h:' || (extract(hour from this.e - this.s)); ret := ret || ' ' || 'm:' || (extract(minute from this.e - this.s)); ret := ret || ' ' || 's:' || (extract(second from this.e - this.s)); RETURN ret; END; FUNCTION hour (this IN OUT NOCOPY tTimer) RETURN NUMBER IS h NUMBER :=NULL; BEGIN h := (extract(hour from this.e - this.s)); RETURN h; END; FUNCTION minute (this IN OUT NOCOPY tTimer) RETURN NUMBER IS m NUMBER :=NULL; BEGIN m := (extract(minute from this.e - this.s)); RETURN m; END; FUNCTION second (this IN OUT NOCOPY tTimer) RETURN NUMBER IS s NUMBER :=NULL; BEGIN s := (extract(second from this.e - this.s)); RETURN s; END; END;
Il suo utilizzo è molto semplice.
A seguire un esempio:
DECLARE t1 CRONO.tTimer; --Variabile di tipo cronometro --Codice che consuma tempo PROCEDURE NOP(cycle IN NUMBER)IS BEGIN FOR i in 1..cycle LOOP DECLARE c NUMBER := 0; BEGIN select 1 into c from dual; END; END LOOP; END; BEGIN --Il cronometro t1 viene creato ed avviato t1 := CRONO.new(); NOP(cycle=>1000); --Il cronometro t1 viene fermato CRONO.stop(t1); --Si stampa il tempo misurato dal cronometro t1 DBMS_OUTPUT.PUT_LINE('Tempo trascorso A:' || CRONO.time(t1)); --Si resetta il cronometro t1 CRONO.reset(t1); NOP(cycle=>500); --Il cronometro t1 viene fermato CRONO.stop(t1); --Si stampa il tempo misurato dal cronometro t1 DBMS_OUTPUT.PUT_LINE('Tempo trascorso B:' || CRONO.time(t1)); END;