PABLO.BLOG.BR
Artigos
Eventos
Livros
Slides
Vídeos
Matérias
Sobre
Contato
Banco de dados em memória? Não, cache de objetos!
Como aumentar o desempenho na busca de objetos
Você já deve ter passado por algum problema de desempenho! Quem nunca passou. Aquele monte de SQL complexo para lá e para cá, análises de queries sem fim, você tentando otimizar o máximo possível, resumindo queries, eliminando outras, criando índices, e mesmo assim o programa está lento por que se você tirar mais alguma query tudo irá parar de funcionar... Então você pensa "Como seria bom se todos dados estivessem em memória, seria muito mais rápido". Neste artigo falaremos em como acelerar o desempenho de uma aplicação mantendo objetos de negócio em memória. Esta estratégia já foi aplicada em aplicações críticas em grandes organizações e mostrou ganhos de até 100% no desempenho de rotinas complexas. Vamos ver como aplicar. Em primeiro lugar, para essa abordagem funcionar, é importante ler este outro artigo "Pensando em Objetos não em SQL para construir uma Aplicação" (http://www.adianti.com.br/forum/pt/view_876?pensando-em-objetos-nao-em-sql-para-construir-uma-aplicacao), isto por que a estratégia que vamos utilizar é de cache de objetos, não de datasets. Bancos de dados como o PostgreSQL possuem o recurso de cache de datasets, ou seja, de páginas de consulta. Assim, se você repetir a mesma consulta, poderá se beneficiar do cache. Nossa estratégia é em nível de aplicação, ou seja, no PHP, e o objetivo é manter objetos inteiros na memória para que, quando eles forem necessários, não seja preciso carregar a partir do banco de dados. Como disse, para esta estratégia funcionar, é preciso modelar, e construir a aplicação somente em torno de objetos. Com isso, esqueça aquelas queries enormes. A aplicação funcionará por meio de relacionamento entre objetos. Dessa forma, se você precisar de uma lista de todos os alunos de uma determinada turma, no lugar de fazer uma query que já traz vários dados para a memória de uma única vez, como no SQL a seguir: ```sql SELECT aluno.nome, cidade.nome, estado.nome FROM turma, matricula, aluno, cidade, estado WHERE turma.id = matricula.id_turma AND matricula.id_aluno = aluno.id AND aluno.id_cidade = cidade.id AND cidade.id_estado = estado.id AND turma.id = 10 ``` Voce fará do jeito a seguir, percorrendo uma série de objetos relacionados por meio de associações. Certamente construirmos um SQL com Joins tem desempenho superior à buscar cada objeto relacionado sempre que ele for necessário e provavelmente algum DBA deve estar se retorcendo agora em alguma cadeira por aí. Mas vamos por partes. ```sql disciplina->nome; print $turma->disciplina->curso->nome; foreach ($turma->getMatriculas() as $matricula) { print $matricula->aluno->nome; print $matricula->aluno->cidade->nome; print $matricula->aluno->cidade->estado->nome; } ``` Tornar o código legível é só o primeiro passo. Agora devemos torná-lo eficiente. Para vamos usar cache de objetos em memória. Para tal, pegamos tabelas relativamente pequenas (até 10 mil registros) e ativamos o cache delas. A não ser que você tenha MUITA memória, não é possível armazenar tabelas grandes (500 mil registros) em memória sob a pena de ficar sem RAM para o processamento das outras operações. É importante lembrar que um objeto em memória ocupa mais espaço do que somente os seus dados. Neste caso, podemos ligar cache para as tabelas de cidade, e estados. Eventualmente para alunos e disciplinas também. Já turmas tendem a surgir todo o semestre e a tabela tende a ficar muito grande. Nesse caso o cache pode ocupar muito espaço da RAM. O cache de objetos no Adianti funciona por que utilizamos o padrão de projeto Active Record. Assim, cada registro do banco de dados é tratado como um objeto em memória. O framework possui de maneira nativa uma classe chamada TAPCache, que se comunica com o APC do PHP. Para quem não sabe, o APC permite armazenar variáveis em memória RAM. O funcionamento se dá como exposto na figura a seguir. Sempre que um objeto é gravado pelo método store(), ele é gravado tanto no banco de dados (a), quanto no cache (d). Agora, sempre que um objeto for requisitado por meio da instanciação direta (Ex: new Estado(10)), ou indireta ($matricula->aluno->cidade->nome), primeiro o framework verifica se o objeto está na memória RAM (c). Caso encontrado, ele é disponibilizado imediatamente para a aplicação. Caso ele não esteja na memória RAM (c), então ele é carregado do banco de dados (b), e gravado na memória RAM (d), para então ser disponibilizado para a aplicação. ![Cache](http://www.adianti.com.br/forum/pt/post-images/cache.png "Cache") Este recurso vem desabilitado por padrão. Mas para ligar é muito simples. Em primeiro lugar é preciso ter o APC instalado (apt-get install php5-apcu). E em seguida, ligar o cache nas classes que você deseja manter em memória. É importante lembrar que os objetos são carregados no cache na medida em que são acessados pela primeira vez. Veja a linha com a definição da constante CACHECONTROL. Você poderá usar a classe nativa TAPCache, ou indicar ali outra classe para manipular o cache. Você poderá implementar uma classe que armazena os dados em Memcached, por exemplo. A classe indicada deverá implementar a interface AdiantiRegistryInterface. ```php
Please enable JavaScript to view the
comments powered by Disqus.