Olá pessoal, tudo bem com vocês?
Neste artigo vou demonstrar como utilizar o recurso de Short-Circuit, para tornar as condicionais dos códigos mais eficientes.
A maiorias das linguagens de programação suportam este recurso, que propõe que, quando aplicada mais de uma condição em uma cláusula de decisão, assim que a primeira seja atendida, as próximas são descartadas.
Por exemplo:
DECLARE<br /> v_numero INTEGER := 100;<br /> BEGIN<br /><br /> IF (v_numero > 0) AND (v_numero / 2) = 0 THEN<br /> DBMS_OUTPUT.PUT_LINE('A Divisão resulta um valor par positivo');<br /> END IF;<br /> END;Veja acima que, para ser visualizada a mensagem, as duas condições devem ser satisfeitas. Caso a primeira condição não seja satisfatória (v_numero > 0), o Oracle não verifica a segunda condição ((v_numero / 2) = 0).
Podemos utilizar isso ao favor do desempenho da aplicação. Abaixo, vamos montar o cenário para efetuarmos os testes de desempenho.
01. Crie a estrutura da tabela onde serão inseridos os movimentos ocorridos no estoque.
create table TB_MOVIMENTO<br />(<br /> ID_MOVIMENTO NUMBER primary key,<br /> DT_MOVIMENTO DATE,<br /> QTD_MOVIMENTADA NUMBER(4),<br /> COD_ITEM VARCHAR2(6)<br />);02. Iremos incluir algumas movimentações de estoque algo em torno de 10 mihões registros, que serão geradas aleatoriamente, para isso utilizarei a package dbms_random, esta proveniente da própria instalação do banco de dados.
declare<br />v_dt dbms_sql.date_Table; --Cria vetor do tipo data<br />v_qtd dbms_sql.Number_Table; --Cria vetor do tipo numérico<br />v_qtd_registro NUMBER := 10000000; --Quantidade de registro<br />begin<br /><br /><br /> --Gera os registro de data de movimento em um dia.<br /> for dd in 1..v_qtd_registro loop <br /><br /> v_dt(dd) := SYSDATE - dbms_random.value(1,365); <br /><br /> end loop; <br /><br /> --Termina o processo<br /> dbms_random.terminate;<br /><br /> --Popular as datas geradas aleatoriamente<br /> dbms_random.seed(99999);<br /><br /> --Gera os registros de quantidade movimentada<br /> for dd in 1..v_qtd_registro loop <br /> v_qtd(dd) := dbms_random.value(1,100); <br /> end loop; <br /><br /><br /> for dd in 1..v_dt.count loop<br /><br /> --Insere as movimentações<br /> insert into tb_movimento<br /> (id_movimento, dt_movimento, qtd_movimentada, cod_item)<br /> values<br /> (dd, v_dt(dd), v_qtd(dd), 'CDROM');<br /><br /> IF(dd/500 = 0)THEN<br /><br /> COMMIT;<br /><br /> END IF;<br /><br /> end loop; <br /><br /> commit;<br />end; Após criada nossa estrutura, vamos efetuar os testes.
Em nosso cenário, o programa deve listar se a quantidade de movimentações ocorridas no mês 06 é maior que 10 mil registros. Para contar esses registros utilizarei uma função.
Primeiramente, vamos fazer do modo mais lento, colocaremos a clausula que demanda mais tempo em primeiro no IF.
SQL> DECLARE<br /><br /> FUNCTION FNC_QTD_MES(P_MES IN VARCHAR2) RETURN NUMBER IS<br /> V_QTD NUMBER;<br /> BEGIN<br /> SELECT COUNT(*)<br /> INTO V_QTD<br /> FROM TB_MOVIMENTO<br /> WHERE TO_CHAR(DT_MOVIMENTO, 'mm') = P_MES;<br /><br /> RETURN V_QTD;<br /><br /> END FNC_QTD_MES;<br /><br /> BEGIN<br /><br /> IF (FNC_QTD_MES(TO_CHAR(SYSDATE, 'mm')) > 10000 AND<br /> TO_CHAR(SYSDATE, 'mm') = '06') THEN<br /><br /> DBMS_OUTPUT.PUT_LINE(A => 'A quantidade de movimentos para o mês 6 é superior à 10 mil registros!');<br /><br /> END IF;<br /><br /> END;<br /> /<br /><br />PL/SQL procedure successfully completed in 19.391 secondsVeja que acima, sempre a função será chamada para o determinar se a condição é verdadeira em todas as execuções do processo. Caso a função retorne mais de 10 mil, a próxima clausula também será verificada.
Podemos ganhar em performace se invertemos as clausulas. Assim, primeiramente será verificado se o mês corrente é Junho, caso não seja, não será executada a função.
SQL> DECLARE<br /><br /> FUNCTION FNC_QTD_MES(P_MES IN VARCHAR2) RETURN NUMBER IS<br /> V_QTD NUMBER;<br /> BEGIN<br /> SELECT COUNT(*)<br /> INTO V_QTD<br /> FROM TB_MOVIMENTO<br /> WHERE TO_CHAR(DT_MOVIMENTO, 'mm') = P_MES;<br /><br /> RETURN V_QTD;<br /><br /> END FNC_QTD_MES;<br /><br /> BEGIN<br /><br /> IF (TO_CHAR(SYSDATE, 'mm') = '06' AND FNC_QTD_MES(TO_CHAR(SYSDATE, 'mm')) > 10000) THEN<br /><br /> DBMS_OUTPUT.PUT_LINE(A => 'A quantidade de movimentos para o mês 6 é superior à 10 mil registros!');<br /><br /> END IF;<br /><br /> END;<br /> /<br /><br />PL/SQL procedure successfully completed in 0 secondsApós inverter a condição, verificando primeiro se a data de execução do processo é o Mês Junho, ganhamos baixamos o tempo de 19 segundos para 0 segundo.
Conclusão
Veja que aquela máxima de a ordem dos fatores não altera o resultado não é plenamente verdade para as condicionais. Claro que existe re-salvas, mas colocar primeiramente as clausulas de menor tempo de execução, pode ajudar com o desempenho do processo.
Abraços,






