Pular para o conteúdo
Visualizando 7 posts - 1 até 7 (de 7 do total)
  • Autor
    Posts
  • #94125
    facc
    Participante

      Bom dia!

      tenho essa procedure

      CREATE OR REPLACE PROCEDURE CYBELAR_RES_NRSORTE(P_LOJA IN varchar2,
      P_PDV IN VARCHAR2,
      P_QTD IN NUMBER,
      P_ORIGEM IN NUMBER,
      P_NROSORTE OUT varchar2,
      P_CONFIRMA OUT NUMBER) is
      /***************************************************************
      * PROCEDURE : CYBELAR_RES_NRSORTE *
      * OBJETIVO : RESERVAR O NRSORTE P/ A LOJA E "ESCONDER" *
      DAS DEMAIS LOJAS E OUTRAS RESERVAS *
      * CRIACAO : 08/05/2009 *
      * ALTERADO : 29/04/2010 - ADD CAMPO P_ORIGEM - COMERCIALIZACAO *
      * VERSAO : 1.0 *
      * AUTOR : FABIO A. CAMPOS CRUZ - *
      ****************************************************************/
      look_error exception;

      pragma exception_init(look_error, -54);

      i number := 1;

      retorno_nrsorte varchar2(5);
      ListaNrsorte varchar2(1000);
      RETORNOCONFIRMA NUMBER;
      erro_int varchar2(1000);
      vc_dir_log varchar2(100);
      vc_id_log varchar2(7) := 'CYBELAR';
      vc_arq_log varchar2(60) := 'NRSORTE_' || to_char(sysdate, 'DDMMYY') ||
      '.LOG';
      vc_nome_pgm varchar2(50) := 'PDV_NRSORTE';
      vu_file utl_file.file_type;

      VN_QTREG NUMBER := 0;

      /*cursor cur_nrosorte is
      --cursor pega numeros "livres"
      select nrosorte
      from cybelar_nrosorte
      where flguso = 0
      AND (LOJA IS NULL OR LOJA = '')
      and rownum <= 1; res cur_nrosorte%rowtype;*/ begin BEGIN SELECT PINT_NM_DIRETORIO_LOG INTO VC_DIR_LOG FROM GEMCO_PARAMETRO_INTERFACE PINT, GEMCO_SISTEMA SIST WHERE PINT.PINT_CD_SISTEMA = SIST.SIST_CD_SISTEMA AND SIST.SIST_DS_SISTEMA = vc_nome_pgm; EXCEPTION -- SE não EXISTIR INFORMAR O DIRETORIO ONDE DEVERA SER -- GERADO O LOG DE OCORRENCIAS WHEN NO_DATA_FOUND THEN VC_DIR_LOG := '/integra/Log'; WHEN TOO_MANY_ROWS THEN VC_DIR_LOG := '/integra/Log'; WHEN OTHERS THEN VC_DIR_LOG := '/integra/Log'; END; begin vu_file := utl_file.fopen(vc_dir_log, vc_arq_log, 'r'); utl_file.fclose(vu_file); exception when others then sp_int_gemco_gera_log('INICIO DO LOG', vc_dir_log, vc_id_log, vc_arq_log, sysdate, null, vc_nome_pgm, 0, 0, 0); end; --open cur_nrosorte; FOR rNrSorte IN 1 .. P_QTD loop --fetch cur_nrosorte into res; --if CYBELAR_LCK_REGISTRO(res.nrosorte) > 0 then
      BEGIN

      LOCK TABLE CYBELAR_NROSORTE IN EXCLUSIVE MODE;

      SELECT NRO.NROSORTE
      INTO retorno_nrsorte
      FROM CYBELAR_NROSORTE NRO
      WHERE LOJA IS NULL
      AND FLGUSO = 0
      AND TO_CHAR(MES_ANO, 'YYYYMM') = TO_CHAR(ADD_MONTHS(SYSDATE, 1), 'YYYYMM')
      AND ROWNUM <= 1 FOR UPDATE NOWAIT; ListaNrsorte := retorno_nrsorte || '|' || ListaNrsorte; UPDATE CYBELAR_NROSORTE SET FLGUSO = 1, LOJA = P_LOJA, PDV_CAIXA = P_PDV, DATANRSORTE = SYSDATE, IDENTORIG = P_ORIGEM WHERE NROSORTE = retorno_nrsorte AND TO_CHAR(MES_ANO, 'YYYYMM') = TO_CHAR(ADD_MONTHS(SYSDATE, 1), 'YYYYMM'); COMMIT; EXCEPTION WHEN look_error THEN NULL; END; RETORNOCONFIRMA := 0; --end if; VN_QTREG := VN_QTREG + 1; end loop; COMMIT; --close cur_nrosorte; IF VN_QTREG = 0 THEN ERRO_INT := 'ERRO AO RESERVAR O NRSORTE (' || P_NROSORTE || ') PARA A LOJA ' || P_LOJA || '.'; RETORNOCONFIRMA := 1; ELSE ERRO_INT := 'RESERVADO COM SUCESSO (' || ListaNrsorte || '). LOJA ' || P_LOJA; RETORNOCONFIRMA := 0; END IF; sp_int_gemco_gera_log('GERA LOG', vc_dir_log, vc_id_log, vc_arq_log, sysdate, erro_int, vc_nome_pgm, 0, 0, 0); sp_int_gemco_gera_log('FIM LOG', vc_dir_log, vc_id_log, vc_arq_log, sysdate, null, vc_nome_pgm, 0, 0, 0); COMMIT; P_CONFIRMA := RETORNOCONFIRMA; P_NROSORTE := ListaNrsorte; end cybelar_res_nrsorte;

      Como poderia melhorar a performance? Dou um lock table pelo motivo da tabela conter números para sorteio, portando deve ser um número único para as 73 lojas da rede, ou seja, o número 1 sendo reservado não pode ser reservado para mais nenhuma loja. A procedure é acessada praticamente ao mesmo tempo por todas as lojas. Após essa reserva chamo outra procedure dando um update com o nome, telefone, cpf do cliente que adquiriu o número.[/code]

      #94130
      vieri
      Participante

        Porque ao invês do lock table , vc não faz um
        select for update, gerando lock exclusivo apenas nas linhas
        que foram selecionadas perimitindo as outras lojas acessarem
        outros numeros.

        #94133
        facc
        Participante

          Onde eu mudaria?
          Tiro a Linha de Lock Table in exclusive mode;

          e mantenho apenas o select e o update posterior?

          #94135
          vieri
          Participante

            Você está bloqueando a tabela toda,
            e em seguida bloqueando as linhas da sua cláusula
            ,antes do update. Pra mim não faz sentido esse lock table ai.
            Pode rancar. Se vc ja seleciona o nrosorte e mantem bloqueado pra vc o numero da sorte no select e depois realiza o update,
            essa linha se mantêm bloqueada até você confirmar a transação.
            sendo assim nenhuma outra loja irá selecionar a mesma linha irá ficar em waiting for row lock até você confirmar, sendo assim sem o lokc table itá diminuir bastante esses waits por row lock, pois outras loja não precisaram esperar outras processarem ,poderam poderar outros numeros paralelamente e sem se repitir.

            LOCK TABLE CYBELAR_NROSORTE IN EXCLUSIVE MODE;

              SELECT NRO.NROSORTE 
                INTO retorno_nrsorte 
                FROM CYBELAR_NROSORTE NRO 
               WHERE LOJA IS NULL 
                 AND FLGUSO = 0 
                 AND TO_CHAR(MES_ANO, 'YYYYMM') = TO_CHAR(ADD_MONTHS(SYSDATE, 1), 'YYYYMM') 
                 AND ROWNUM &lt;= 1          
            

            FOR UPDATE NOWAIT;

            #94137
            facc
            Participante

              Então se eu tirar o lock table não corro o risco de reservar o mesmo número para mais de uma loja?

              Irei fazer um teste, qualquer coisa volto a postar.

              Obrigado!

              #94146
              vieri
              Participante

                uma demonstração do que ocorre.

                SQL> create table teste_wait as select * from dba_tables ;

                Table created.

                SQL> select table_name from teste_wait where table_name = ‘TB_HISTORICO_ESTOQUE’ for update nowait ;

                TABLE_NAME

                TB_HISTORICO_ESTOQUE

                em outra sessão aberta:

                SQL> select table_name from teste_wait where table_name = ‘TB_HISTORICO_ESTOQUE’ for update nowait ;
                select table_name from teste_wait where table_name = ‘TB_HISTORICO_ESTOQUE’ for update nowait
                *
                ERROR at line 1:
                ORA-00054: resource busy and acquire with NOWAIT specified

                De volta a primeira sessão:

                SQL> commit ;

                Commit complete.

                As linhas são liberadas para outra sessão.

                SQL> select table_name from teste_wait where table_name = ‘TB_HISTORICO_ESTOQUE’ for update nowait ;

                TABLE_NAME

                TB_HISTORICO_ESTOQUE

                Se a sessão em espera fizesse um filtro por qualquer outra tabela,
                conseguiria buscar, diferentemente do lock table que irá bloquear todas as linhas da tabela.

                😉

                #94149
                vieri
                Participante

                  ops..

                  Se a sessão em espera fizesse um filtro por qualquer outro registro,
                  conseguiria buscar, diferentemente do lock table que irá bloquear todas as linhas da tabela.

                Visualizando 7 posts - 1 até 7 (de 7 do total)
                • Você deve fazer login para responder a este tópico.