Sunday, September 21, 2008

Campos Lookup - Uma abordagem racional

Ando lendo em sites e publicações especializadas em Delphi muita coisa sobre campos de lookup e sua utilização em sistemas, como por exemplo as famosas LookupComboBoxes. Geralmente fala-se mal, recomenda-se não utilizar campos lookup. Ou então que sua utilização é muito restrita, e só serve para tabelas contendo poucos registros (exatamente quantos, ninguém fala, certo?).. Coisas que eu ouvia há 10 ou 15 anos, quando quase todo mundo desenvolvia usando os velhos e bons conceitos Cliente/Servidor.

De lá prá cá muita coisa mudou. A banda de internet que a alguns têm em casa é mais rápida que algumas redes que usavam cabos coaxiais em 1995.
Mesmo assim, alguns teimam em usar o mesmo conceito antigo que "não se pode trafegar pela rede meia dúzia de registros que possivelmente não serão usados"... AFFFFF!!!!
Então vejamos... O que é mesmo AJAX? Quanta informação desnecessária é trafegada para dar a uma aplicação web AJAX o seu comportamento?
De qualquer forma, nada melhor que fatos e dados para basear o meu ponto de vista.

Suponha uma tabela "cliente", com a seguinte estrutura:

codigo_cliente - Integer
nome_cliente - varchar(50)
codigo_profissao - Integer

e uma tabela "profissao" com a seguinte estrutura:

codigo_profissao - Integer
descricao_profissao - varchar(30)

Em 99% dos casos eu ouço que não se deveria fazer lookup na tabela de profissões, e sim um JOIN.
Imagine uma consulta típica para um relatório, onde irei listar os clientes e suas profissões. O SQL típico seria:

SELECT c.codigo_cliente, c.nome_cliente, p.descricao_profissao
FROM cliente c
INNER JOIN profissao p
ON c.codigo_profissao = p.codigo_profissao
ORDER BY c.codigo_cliente ASC

Com alguma simplificação podemos assumir um tamanho de registro de dados igual a 84 bytes. Se eu tivesse 2000 clientes, teríamos um pacote de dados de aproximadamente 165 kbytes.

Agora, vejamos por outro lado. Imagine que eu tivesse 2 consultas separadas:
SELECT codigo_cliente, nome_cliente, codigo_profissao
FROM cliente
ORDER BY codigo_cliente ASC

SELECT codigo_profissao, descricao_profissao
FROM profissao

Vamos supor ainda que minha tabela de profissão contivesse 500 registros. O total de dados trafegados seria 58*2000 (clientes) + 34*500 (profissões) = 130 kbytes.

Oras! Eu fiz duas consultas, trouxe toda a tabela de profissões para o lado cliente e ainda tive um tráfego menor???? Hum... Agora, imagine que este relatório é chamado por várias vezes durante a execução do programa?

Quantas vezes por dia a tabela de profissões muda? Talvez sejam adicionadas novas profissões, de vez em quando, mas em sistemas do mundo real isto ocorre muito no início do ciclo de vida do sistema e tende a diminuir - e muito - com o tempo. Não poderíamos carregar a tabela de profissões, digamos na inicialização do sistema, e usá-la como Lookup durante o ciclo de vida da aplicação?

Um mecanismo mais inteligente poderia checar as alterações da tabela de profissões antes de sua utilização (como lookup no relatório, por exemplo) e fazer um refresh sempre que necessário. O ganho de performance tanto de banco de dados quanto da aplicação é significativo.

Alguns conceitos de C/S estão certamente ultrapassados. O pessoal que os usa sem parar para pensar (e principalmente MEDIR) o que acontece de fato em sistemas do mundo real deveria revê-los.