[firebase-br] Melhorar performance - pedido x situação
Tecnobyte Informática
temp2 em tecnobyte.com.br
Seg Set 26 18:06:55 -03 2011
Tenho as seguintes tabelas:
Pedido(
Id INTEGER NOT NULL,
DataEmissao DATE NOT NULL,
...
CONSTRAINT PK_Pedido PRIMARY KEY(Id)
);
PedidoSituacao(
Id INTEGER NOT NULL,
Pedido_Id INTEGER NOT NULL,
Situacao SMALLINT NOT NULL,
DataSituacao DATE NOT NULL,
...
CONSTRAINT PK_PedidoSituacao PRIMARY KEY(Id),
CONSTRAINT FK_PedidoSituacao_Pedido FOREIGN KEY(Pedido_Id)
REFERENCES Pedido(Id) ON DELETE CASCADE
);
CREATE DESC INDEX IN_PedidoSituacao_Id ON PedidoSituacao(Id);
A situação de um pedido pode ser:
1-Aberto
2-Conferido
3-Faturado
4-Enviado
Para obter os dados do pedido com respectiva situação pode-se fazer assim:
SELECT
Pedido.Id,
Pedido.DataEmissao,
PedidoSituacao.Situacao,
PedidoSituacao.DataSituacao,
...
FROM Pedido
JOIN PedidoSituacao ON PedidoSituacao.Id =
(SELECT FIRST 1 PedidoSituacao.Id FROM PedidoSituacao
WHERE PedidoSituacao.Pedido_Id = Pedido.Id
ORDER BY PedidoSituacao.Id DESC)
...
Para simplificar criei um campo calculado assim:
ALTER TABLE Pedido
ADD PedidoSituacao_Id =
(SELECT FIRST 1 PedidoSituacao.Id FROM PedidoSituacao
WHERE PedidoSituacao.Pedido_Id = Pedido.Id);
Desta forma o JOIN mostrado acima fica mais simples:
...
FROM Pedido
JOIN PedidoSituacao ON PedidoSituacao.Id = Pedido.PedidoSituacao_Id
...
As duas formas apresentadas acima funcionam razoavelmente bem. Porém para
filtrar pela última situação do pedido geralmente fica lento se houver uma
grande quantidade de pedidos (dezenas de milhares, por exemplo).
Para contornar este problema, troquei o campo calculado
(Pedido.PedidoSituacao_Id) por um campo físico:
ALTER TABLE Pedido
ADD PedidoSituacao_Id INTEGER,
ADD CONSTRAINT FK_Pedido_PedidoSituacao FOREIGN KEY(PedidoSituacao_Id)
REFERENCES PedidoSituacao(Id) ON DELETE SET NULL;
E criei trigger para atualizar este campo toda vez que inserir, alterar ou
excluir a situação de um pedido:
SET TERM ^ ;
CREATE OR ALTER TRIGGER TG_PedidoSituacao_Antes FOR PedidoSituacao AFTER
INSERT OR UPDATE OR DELETE AS
DECLARE VARIABLE Pedido_Id INTEGER;
BEGIN
IF (INSERTING OR UPDATING) THEN
Pedido_Id = NEW.Pedido_Id;
ELSE
Pedido_Id = OLD.Pedido_Id;
UPDATE Pedido SET PedidoSituacao_Id =
(SELECT FIRST 1 PedidoSituacao.Id FROM PedidoSituacao
WHERE PedidoSituacao.Pedido_Id = Pedido.Id)
WHERE Pedido.Id = :Pedido_Id;
END^
NOTA! Os comandos acima são apenas para ilustrar a situação. Talvez esteja
com erros de sintaxe.
Depois que fiz isto, a consulta de pedidos pela última situação ficou ótima,
mas ficou com cara de gambiarra!
Alguém sabe uma forma mais adequada e profissional de se fazer isto?
Atenciosamente.
Daniel P. Guimarães
Tecnobyte Informática
www.tecnobyte.com.br
Mais detalhes sobre a lista de discussão lista