- Este tópico contém 6 respostas, 2 vozes e foi atualizado pela última vez 15 anos, 10 meses atrás por
vieri.
-
AutorPosts
-
21 de maio de 2010 às 4:19 pm #94125
facc
ParticipanteBom 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
BEGINLOCK 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]
21 de maio de 2010 às 6:20 pm #94130vieri
ParticipantePorque 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.21 de maio de 2010 às 6:30 pm #94133facc
ParticipanteOnde eu mudaria?
Tiro a Linha de Lock Table in exclusive mode;e mantenho apenas o select e o update posterior?
21 de maio de 2010 às 6:48 pm #94135vieri
ParticipanteVocê 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 <= 1FOR UPDATE NOWAIT;
21 de maio de 2010 às 7:22 pm #94137facc
ParticipanteEntã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!
21 de maio de 2010 às 9:01 pm #94146vieri
Participanteuma 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 specifiedDe 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.😉
21 de maio de 2010 às 11:05 pm #94149vieri
Participanteops..
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. -
AutorPosts
- Você deve fazer login para responder a este tópico.