[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