Friday, October 17, 2008

Cache de DataSets em aplicações multi-camadas II

Identificando unicamente um DataSet.

Bem, quanto aos requisitos do post anterior:

1) O gerenciador do cache deverá ser capaz de identificar unicamente um DataSet

Como identificar unicamente um DataSet obtido a partir de uma consulta a um banco de dados? Bem, no meu caso os DataSets são resultado de uma consulta SQL. Independentemente do mecanismo de acesso a dados, quando se utiliza SQL em geral temos um objeto de query (TADOQuery, TSQLQuery, etc.) e o mesmo possui uma propriedade SQL do tipo TStrings. A string que contém o comando SQL é, com certeza, um identificador único de uma query certo? Mas a string não é ideal para um identificador único, pois pode ser gigante, difícil de comparar, etc. O melhor mesmo é gerar um hash a partir do SQL. SQL diferentes deverão gerar hashes únicos com uma probabilidade de colisão suficientemente baixa.
No meu caso, optei por usar não um hash propriamente dito, mas um CRC. Optei por usar o CRC64 que me possibilita ter uma probabilidade de colisão suficientemente baixa para uma aplicação de qualquer tamanho.
Quem tiver curiosidade sobre esta probabilidade, segue um teste com o algoritmo:

http://apollo.backplane.com/matt/crc64.html

Resumindo, a probabilidade de colisão é da ordem de 1 colisão para 2E12 mensagens, o que acredito que seja mais do que satisfatório.

Então, passamos nossa expressão SQL por um algoritmo de geração de CRC64 e obtemos um identificador único para nossa sentença SQL, como por exemplo CF247CF5C26FF896.

Mas temos ainda um problema: A mesma sentença de SQL executada contra dois bancos de dados diferentes (mas com estrutura compatível, como por exemplo um banco de dados de produção e outro de homologação) possuem identificadores idênticos porém o DataSet resultante é diferente.
Neste caso devemos incorporar ao identificador único do DataSet um identificador do banco de dados. O banco de dados geralmente é identificado pelo servidor, nome do banco ou schema, usuário, etc. Muitas formas são possíveis para se gerar um identificador do banco de dados. No meu caso, usando ADO como mecanismo de acesso a dados, optei por seguir a mesma linha de raciocínio e usar o CRC64 da string de conexão (propriedade ConnectionString do TADOConnection).

Então, com o CRC do SQL mais o CRC da string de conexão eu tenho um identificador único para meu DataSet que funcionará como índice. Mais sobre isto em breve.

4 comments:

Jack said...

Alexandre, legal demais essa série de artigos sobre cache de dados. Fiquei curioso para saber o desfecho. Algumas idéias borbulharam aqui na cabeça sobre o cache de dados. Será que vc vai chegar ao nível de calcular o Hash dos próprios dados? Seria interessante. O hash do SQL também inclui os parâmetros? Outra coisa interessante.

[]'s

Jackson

Alexandre Machado said...

Olá Jackson! Bom saber que tenho leitores ilustres lendo meu modesto blog! :)

Seguinte, eu vou ver se escrevo a parte III esta semana ainda. Estou em fase final de implementações e testes e digamos que está funcionando melhor do que eu previa.

Quanto às suas perguntas...
1) Hash dos dados: sinceramente não cheguei a pensar nisso. Não sei se seria viável algo a este ponto pois o cálculo do hash exige um processamento razoável.
2) Hash do SQL com parâmetros: Sim, se o SQL possui parâmetros, o hash inclui também uma "lista" contendo os pares de dados nome do parametro=valor do parametro.

Abraço!

Adecio Cavalheiro Junior said...

Legal gostei da ideia, acha que seria demais fazer o hash ou crc64 a partir do data do clientdataset ?

Adecio Cavalheiro Junior said...

Deixa tirar uma duvida, é que estou agora começando a implementar a ideia de cache, uma mesma consulta pode me retornar dados diferente tipo uma consulta de pedidos gerados, tenho 70 usuários gerando pedidos e outra equipe faturando por isso tenho um alto indice de consultas e estou pensando em colocar isso em cache mas estou meio perdido de como fazer isso ainda