domingo, 6 de janeiro de 2008

Dicas de otimização e segurança

Olá, amigos. Depois de muito tempo away deste blog volto a publicar algumas informações coletadas e experimentadas.

Estudei bastante e fiz várias anotações durante os últimos meses. Além deste post se preparem para mais novidades legais em breve.

Neste reinício trago a vocês dicas sobre otimização e segurança. Algumas boas práticas que espero ser de valia.

Uma das decisões mais importantes durante o desenvolvimento de um sistema é onde implementar as regras do negócio. É comum deixar as regras ao encargo do linguagem de programação, mas quero mostrar que o melhor lugar para se fazer isso, sempre que possível, é no banco de dados.

Quando se implementa a lógica do negócio na linguagem de programação algumas coisas aumentam, como o tempo de desenvolvimento, o volume de códigos e a dificuldade em se fazer manutenção. Além de diminuir a portabilidade da aplicação (no caso de uma migração por exemplo).

Isso sem falar no ponto mais crítico: o aumento do tráfego e do processamento.

Vou exemplificar com um cenário comum - Apache 2, PHP 5 e MySQL 5.

Quando se tem a lógica implementada nos scripts/classes PHP, o fluxo segue mais ou menos como na figura:


Explicando... o cliente faz uma requisição ou envia um form. Estas informações são recebidas pelo servidor web que chamará o engine. O engine irá processar as requisições, se conectar com o banco de dados, enviar a(s) query(ies), processar a(s) resposta(s), fechar a conexão com o banco de dados, preparar a saída, repassá-la para o servidor e este por fim enviará para o cliente.

Isso é o processo que acontece geralmente em qualquer aplicação. Mas note que quando se deixa a regra dos negócios para o engine resolver, podem ser necessárias várias conexões e consultas ao banco de dados, e é aí onde o sistema perde performance - e muita.

A meta é diminuir este gargalo e aliviar este ponto crítico (a conversa entre o engine e o banco de dados). Deixando a lógica de dados implementada no banco de dados, o engine que trabalha com ele fará menos conexões, diminuirá a carga de processamento e melhorará o tempo de resposta, além de deixar o sistema mais robusto.

Assim, é altamente recomendável lançar mão de recursos como Views, Triggers, Procedures, Functions, e fazer um bom uso de índices e chaves disponíveis no banco de dados.

Digo isso porque tive uma experiência realmente dura em um sistema onde TODA a lógica dos dados estava implementada com o design pattern MVC. E para retornar um simples relatório com 50 linhas o sistema demorava uns 6 minutos - simplesmente crítico.

O problema é que haviam várias tabelas com relação Muitos-para-Muitos e a cada linha que se queria obter era necessário realizar uma série de queries e filtragens. Posso citar um dos casos onde para cada usuário era feita uma consulta numa tabela de relacionamento que retornava cerca de 8 chaves, que depois seriam pesquisadas em outra tabela, comparados, validados segundo sua data, organizados (aí já tinha apenas uns 2 ou 3 registros que realmente seriam úteis para o relatório), para depois fazer mais queries em duas ou três tabelas.

Ou seja para produzir uma linha, era necessário um volume de tráfego e processamento absurdo, sendo que isso poderia ser facilmente resolvido (ou pelo menos fortemente otimizado) com a criação de uma view e de uma function.

Aqui cabe um adendo: a diferença entre o modelo entidade-relacional dos bancos de dados e do que se pode implementar na programação orientada a objeto se chama impedância, e as boas práticas aqui citadas visam diminuir este problema. Eis um bom artigo aqui: http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=70

Então a dica de otimização é essa: implemente a lógica de dados sempre que possível na própria base de dados.

Mas e a linguagem de programação seria útil para quê então?
Ora, para validar os dados enviados, fazer a conexão, enviar e receber dados do servidor, enviar e-mails, montar páginas dinamicamente... as mesmas coisas que antes. O que quero dizer é que ao invés de rechear seus scripts e classes com ifs, elses, switch cases e queries, você deve diminuir isso e usar apenas onde for realmente necessário.

Em relação à segurança, ela aumenta quando se adota esse procedimento e estes cuidados. Além disso você terá mais tempo livre para criar validações nos seus scripts server-side, e contará com mais uma camada de validação - a do servidor de bancos de dados.

É mais econômico para o sistema você checar se, por exemplo, um id existe numa determinada tabela do que fazer uma query select e depois uma comparação no script.

Algo assim: ao invés de fazer
<?
...
$valid_user = 0;
$sql = "SELECT 1 FROM users WHERE id = $posted_id";
$result = mysql_query($sql);
$x = mysql_fetch_assoc($result);
if ($x) {
$valid_user = 1;
}

if ($valid_user == 1) {
$sql_2 = "INSERT INTO...";
...
}
...

?>


Faça assim:
<?
$sql = INSERT INTO table_x VALUES ($x,$y,$z) WHERE $z INTO (SELECT id FROM users);
?>


Ou que você crie uma function no banco de dados para fazer isso.

Até mais.
-----------
keepReading

Nenhum comentário:

Postar um comentário