[firebase-br] Lentidao em Base de dados Grande
Eduardo Bahiense
eduardo em icontroller.com.br
Ter Jan 26 11:48:42 -03 2010
Olá Rodrigo
Desculpe a demora, eu estive fora esses dias.
Bem, não vou discutir sua lógica, até porque não lido muito com
controles de estoque.
A cada inserção, primeiro você verifica a tabela ITENS pelo campo
SEQUENCIAL, então, perguntas:
1. existe um ínidce no campo SEQUENCIAL na tabela ITENS?
2. o valor em SEQUENCIAL é sempre único? ou pode ter mais de uma linha
na tabela com o mesmo SEQUENCIAL?
Depois que você determina o tipo de ENTRADA, atualiza PRODUTOS pela
condição "PRODUTOS.CODIGO = NEW.CODIGOPRODUTO AND NEW.TIPO='P' AND
(NEW.TIPOVENDA='V' OR NEW.TIPOVENDA='O' OR NEW.TIPOVENDA='H')". Perguntas:
1. Você tem um índice em PRODUTOS iniciando por "CODIGO, TIPO"?
2. Para um mesmo PRODUTO, TIPO, em média, quantos TIPOVENDA existem?
Se esse número não for muito pequeno, esse UPDATE pode ser lento, pois
ele só poderá ir com índice até "CODIGO,TIPO", depois, terá que varrer
sequencial até que mude o valor de CODIGO.
Outra coisa que você poderia otimizar aqui seria criar um campo
"TIPOUPDATE" e pré-marcar com 0 ou 1, por exemplo, quando TIPOVENDA for
H,V ou O, colocando esse campo no índice "CODIGO, TIPO, TIPOVENDA", e
evitando o "(NEW.TIPOVENDA='V' OR NEW.TIPOVENDA='O' OR
NEW.TIPOVENDA='H')", substituindo por "NEW.TIPOVENDA=1", deixando a
operação 100% indexada.
Outra coisa que requer um pouco mais de processamento e que você poderia
otimizar no seu código é evitar o "COALESCE(PRODUTOS.ESTOQUEU2,0)",
forçando, nas inserções nessa tabela o NOT NULL. Se estamos falando em
otimizar, tudo pode contribuir um pouquinho.
Se o planejamento de índices estiver correto, não vejo porque existir
demora nessa operação, pois, por fim, você lidaria com um SELECT
retornando um CHAR1 ('S','N'), que leu somente um registro na tabela, e
um UPDATE afetando, igualmente, somente uma linha.
Um terceiro problema possível, como disse o Welkinson, seria se você
fizesse um grande número de inserções ao mesmo tempo, como em um
processo BAT, e só fizesse o COMMIT no final, ocasioando inserções mais
lentas conforme as transações não COMMITADAS fossem se acumulando.
Observe que, ainda que as tabelas consultadas tenham mais de 800.000
registros, se o planejamento de índices estiver adequado, a quantidade
de leituras é mínima, e, repito, não vejo motivos para gargalos.
Eduardo
Rodrigo escreveu:
> Eduardo, acho que achei o problema, acho que esta nessa trigger:
>
>
> CREATE TRIGGER IT_PEDIDO_ESTOQUE FOR ITENS
> ACTIVE AFTER INSERT OR UPDATE POSITION 0
> AS
> DECLARE VARIABLE ENTRADA CHAR(1);
> DECLARE VARIABLE TIPO CHAR(1);
> BEGIN
> IF (INSERTING) THEN BEGIN
> SELECT ENTRADA FROM ITENS WHERE SEQUENCIAL=New.Sequencial // nessa linha
> pesquiso no banco de dados da tabela itens, quase 800000 registros para
> achar se entrada é 'S' ou 'N')
> INTO :ENTRADA;
> if (ENTRADA = 'S') then
> UPDATE PRODUTOS SET PRODUTOS.DATAUAT=CURRENT_DATE, PRODUTOS.ESTOQUEU2 =
> COALESCE(PRODUTOS.ESTOQUEU2,0) - NEW.QTDU2 WHERE PRODUTOS.CODIGO =
> NEW.CODIGOPRODUTO AND NEW.TIPO='P' AND (NEW.TIPOVENDA='V' OR
> NEW.TIPOVENDA='O' OR NEW.TIPOVENDA='H');
> if (ENTRADA = 'E') then
> UPDATE PRODUTOS SET PRODUTOS.DATAUAT=CURRENT_DATE, PRODUTOS.ESTOQUEU2 =
> COALESCE(PRODUTOS.ESTOQUEU2,0) + NEW.QTDU2 WHERE PRODUTOS.CODIGO =
> NEW.CODIGOPRODUTO AND NEW.TIPO='P' AND (NEW.TIPOVENDA='V' OR
> NEW.TIPOVENDA='O' OR NEW.TIPOVENDA='H');
> END ELSE
> IF (UPDATING) THEN BEGIN
> SELECT ENTRADA FROM ITENS WHERE SEQUENCIAL=New.Sequencial // nessa
> linha pesquiso no banco de dados da tabela itens, quase 800000 registros
> para achar se entrada é 'S' ou 'N')
> INTO :ENTRADA;
> if (ENTRADA = 'S') then
> UPDATE PRODUTOS SET PRODUTOS.DATAUAT=CURRENT_DATE, PRODUTOS.ESTOQUEU2 =
> COALESCE(PRODUTOS.ESTOQUEU2,0) - NEW.QTDDESC WHERE PRODUTOS.CODIGO =
> NEW.CODIGOPRODUTO AND NEW.TIPO='P' AND (NEW.TIPOVENDA='V' OR
> NEW.TIPOVENDA='O' OR NEW.TIPOVENDA='H');
> if (ENTRADA = 'E') then
> UPDATE PRODUTOS SET PRODUTOS.DATAUAT=CURRENT_DATE, PRODUTOS.ESTOQUEU2 =
> COALESCE(PRODUTOS.ESTOQUEU2,0) + NEW.QTDDESC WHERE PRODUTOS.CODIGO =
> NEW.CODIGOPRODUTO AND NEW.TIPO='P' AND (NEW.TIPOVENDA='V' OR
> NEW.TIPOVENDA='O' OR NEW.TIPOVENDA='H');
> END
> END
> ;
>
> nessa trigger eu faço um select na tabela itens para verificar se é
> considerado entrada ou saida da mercadoria no estoque.
>
> ex. se é uma venda coloco "S" no entrada e o sistema vai saber que é
> para diminuir um do estoque, se for devolução "E" vai entrar um no estoque.
>
> testando esse select ele chega a quase 2 segundos só nele, por isso acho
> que esta lento?
>
> Na sua opniao, como vc acha que devo fazer esse controle?, ja quebrei a
> cabeça aqui e nao estou conseguindo achar outro meio...
>
> Grato,
>
> Rodrigo
>
> ______________________________________________
> FireBase-BR (www.firebase.com.br) - Hospedado em www.locador.com.br
> Para saber como gerenciar/excluir seu cadastro na lista, use:
> http://www.firebase.com.br/fb/artigo.php?id=1107
> Para consultar mensagens antigas: http://firebase.com.br/pesquisa
>
Mais detalhes sobre a lista de discussão lista