Dicas de Programação em ambiente Cliente/Servidor 1. Introdução O surgimento da computação Cliente/Servidor estimulou o processo de downsizing nas empresas pois permitia rodar aplicações "pesadas" em micros relativamente baratos com uma velocidade aceitável. Isso foi possível porque, num sistema cliente/servidor, entre outras coisas, o processamento é dividido entre as estações clientes e o servidor central, não sobrecarregando nenhum dos lados e aliviando o tráfego pela rede. No entanto, dependendo da maneira como a aplicação foi planejada, mesmo que você possua a mais potente e avançada combinação de hardware e software, o seu sistema pode se transformar num simples e lento servidor de arquivos. Para ajudá-lo a evitar que isso aconteça, a seguir, iremos discutir algumas providências que podem ser tomadas, começando por um ponto que é crucial: a arquitetura do sistema. 2. Arquiteturas C/S Atualmente existem 4 tipos de arquitetura para as aplicações Cliente/Servidor. As diferenças entre elas giram em torno de uma questão: Quem deve fazer a maior parte do processamento? O Cliente? O servidor? Ambos? Ou existe uma solução melhor? Vamos responder essas questões analisando cada arquitetura, mostrando suas vantagens e desvantagens. O Cliente inteligente Esta arquitetura baseia-se na implementação de duas camadas com cliente inteligente, ou seja, todas as regras de negócios e a inteface com o usuário rodam no cliente, deixando o servidor apenas como um servidor de arquivos. Vantagens 1. 2. Simplicidade de desenvolvimento. Várias ferramentas disponíveis. Desvantagens 1. 2. Excessivo de tráfego na rede, podendo causar travamentos e outros problemas. Modificações nas regras de negócio devem ser feitas em todos os clientes. O Servidor inteligente Baseia-se na implementação de duas camadas com servidor inteligente, ou seja, todas as regras de negócio ficam no servidor localizadas em stored procedures e triggers. Vantagens 1. 2. Melhor performance. Mudanças nas regras de negócios podem ser feitas em um único local: O banco de dados. Desvantagens 1. 2. Excesso de recursos no servidor, podendo causar overhead. Poucas ferramentas de auxílio ao desenvolvedor. Solução Mista Baseia-se numa implementação de duas camadas que combina cliente inteligente com servidor inteligente. Vantagens Boa performance. Desvantagens Quando muda uma regra de negóçio, você tem que determinar onde ela está localizada. Se estiver no cliente, você é obrigado a redistribuir a aplicação. Múltiplas camadas É a tendência do momento. Baseia-se num implementação de múltiplas camadas onde as regras de negócio ficam localizadas em componentes distribuídos (DLL's DCOM). O Front-End seria responsável pela interface com o usuário, e o banco de dados pela consistência das informações. Vantagens 1. 2. 3. Mudanças das regras de negócio podem ser feitas em um único local: O componente. Melhor distinção entre os serviços do sistema: Dados, Regras de negócio e Apresentação. Boa performance. Desvantagens Complexidade no planejamento da aplicação. A seguir vamos relacionar algumas dicas para melhorar a performance de Sistemas C/S, lembrando-se que elas foram levantadas levando-se em conta um sistema com o Visual Basic 5.0 acessando o SQL Server 6.5 via RDO, mas, com poucas excessões, aplicam-se à maioria dos sistemas. 3. Do Lado do Servidor Use o bom senso com referência a normalização Não normalize demais o Banco de dados, pois poderá haver queda de performance. Ir apenas até a 3ª forma normal. Os puristas de bancos de dados relacionais podem ficar incomodados com isso, mas a prática nem sempre reflete a teoria. Evite também usar relacionamentos recursivos por problemas de performance e complexidade de código Poupe o servidor Acessar o Banco de dados através de stored procedures é a maneira mais vantajosa para o desenvolvedor, mas o seu uso indiscriminado pode sobrecarregar o servidor. O ideal é usar o esquema de múltiplas camadas, onde as regras de negócio ficam em componentes separados do BD (DCOM,CORBA, etc.). As stored procedures seriam utilizadas basicamente para efeitos de manutenção e integridade. Outras recursos que podem derrubar o servidor são: - Muitas conexões abertas ao mesmo tempo. - Uso excessivo de server-side cursores. - Uso excessivo de comandos prepare/execute. - Uso excessivo de cursores dinâmicos Faça uso da replicação Segundo pesquisas, a maior parte dos acessos ao banco de dados é para consultas. Por isso, o ideal é você replicar o BD para outros servidores e direcionar as consultas para as réplicas, ficando o servidor central encarregado da manutenção (Insert, Update, etc.). Não use Rules e Defaults Para fazer validações e impor regras de integridade, prefira o uso de Constraints, Triggers e Stored Procedures. Crie índices para os campos críticos Toda vez que você executa um select, o SQL vai traçar um plano de ação para determinar a maneira mais rápida de executá-lo e, se existirem índices criados para os campos envolvidos, ele vai utilizá-los. Não queremos que você crie índices para cada campo que aparece em um select, mas os seguintes campos são candidatos a serem indexados: - Chaves Primárias - Chaves Estrangeiras - Campos usados em operações de join - Campos usados frequentemente em cláusulas Where - Campos usados em pesquisas por faixas de valores Mantenha os índices atualizados O SQL não atualiza automaticamente as estatísticas de acesso aos índices das tabelas. Você precisa fazer isso manualmente através do comando UPDATE STATISTICS. Caso não o faça periodicamente, os comandos SELECT poderão ser realizados sem a ajuda dos índices, ou pior , com dados desatualizados. Use índices Agrupados (Clustered) em campos apropriados Os índices agrupados são índices que ordenam fisicamente a tabela. Os campos candidatos a usarem um índice agrupado são os campos que são frequentemente classificados. Não compensa, no entanto, você definir um índice agrupado para chaves primárias que são sequenciais ou do tipo identity. Desfragmente o Banco periodicamente. Para desfragmentar o banco, copie-o para outro local e depois restaure-o. Isso pode ser feito a cada 6 meses ou mais, dependendo da necessidade. Evite o uso do Tipo VarChar para campos que sofrem muitas atualizações VarChar é um tipo de dados texto que só armazena no banco a quantidade de caracteres realmente utilizada. Se, por um lado, esse tipo de dado economiza um certo espaço em disco, de outro lado ele pode tornar a tabela fragmentada, se o campo sofrer muitas atualizações. 4. Do lado do Cliente Por cliente queremos nos referir tanto à aplicação front-end quanto aos componentes distribuídos que solicitam serviços ao servidor. Moderação no uso de conexões Uma conexão aloca recursos tanto do cliente quanto do servidor. Para evitar sobrecargas, procure abrir a conexão e fechá-la logo em seguida. Estabeleça um sistema que abra a conexão apenas quando ela for necessária e crie um mecanismo que feche a conexão quando ela permanecer inativa por um certo período de tempo. Limite a faixa das consultas Usar sempre comandos SQL que retornem um conjunto mínimo de registros para evitar o tráfego na rede. Nunca use comandos selects sem cláusulas adicionais, procure sempre limitar a faixa de retorno de suas consultas usando where ou having. Mais de uma, preferencialmente. Essa dica vale também para a programação do lado do servidor. Sempre informar ao usuário o que está acontecendo Em consultas mais demoradas, sempre exibir informações sobre o andamento do processo, usando odômetros e outros recursos. Construa rotinas robustas de tratamento de erros, que dêem o máximo de informações. Escolha o modo de acesso apropriado Dê preferêcia por acessar o SQL através do RDO ou ADO. O DAO não é apropriado para acesso Cliente/Servidor e o RDO já está saindo de linha. Veja mais informações no artigo "Formas de acesso a bancos de dados em Visual Basic". Controle o acesso às tabelas O lock de páginas e tabelas é uma das principais causas de travamento das aplicações. O SQL bloqueia a tabela mesmo para leitura, o que é conhecido como read lock. Para minimizar esses problemas, tome as seguintes medidas: - Se possível, execute o comando select sem read lock. - Termine rapidamente as transações Essa dica vale também para a programação do lado do servidor onde, preferencialmente, devem ser controladas as transações. Faça uso dos vários tipos de cursores para suas consultas Através do RDO você pode criar vários tipos de cursores. Escolha aquele que oferece melhor desempenho para o tipo de operação que você quer realizar. Os cursores podem ser classificados quanto à localização, ao tipo, à concorrência e à navegabilidade. Podem se localizar no cliente ou no servidor. Esse último só deve ser usado quando o número de registros retornado à aplicação é muito grande. Quanto ao tipo, os cursores podem ser estáticos ou dinâmicos, sendo os primeiros os que apresentam a melhor perfomance. Com relação a concorrência, prefira os cursores read-only e, quanto à navegabilidade, os forward-only são bem mais rápidos para serem usados em consultas e relatórios. Sempre que possível, use ResultSets do tipo cursor-less . Nas manutenções, evite o uso de cursores Quando você vai atualizar os dados no servidor (Insert,Update,Delete), prefira usar stored procedures ou action queries. Se for usar cursores, prefira a técnica de batch update, que manda os comandos em blocos ao servidor. Escolha o modelo de execução apropriado à tarefa Através do RDO você pode executar comandos através de 3 modos. Veja as vantagens de cada um: Execute Direct - É a maneira mais rápida para executar comandos esporádicos e para executar stored procedures. Para os demais comandos ela é muito lenta. Prepare/Execute - Próprio para executar comandos frequentes. Sua desvantagem é que usa espaço no tempdb. Stored procedures - Deve ser utilizada na maioria dos casos. Armazenar as tabelas pequenas na memória Existem algumas tabelas que são pequenas e não são alteradas frequentemente e portanto podem ser jogadas para a memória (array), evitando assim o acesso ao servidor. 5. Conclusão Se fossemos resumir o que vimos aqui, poderíamos dizer que existem 4 fatores que interferem com o desempenho dos sistemas cliente/servidor, sem levar em conta a arquitetura utilizada: 1. 2. 3. 4. O uso de comandos de consulta sem critérios. O lock de páginas e tabelas sem controle. A sobrecarga no servidor. Indexação inadequada das tabelas Podemos concluir também que o desenvolvimento de aplicações Cliente/Servidor é muito complexo e trabalhoso pois, nesse ambiente, precisamos estudar cada acesso que vamos fazer ao banco de dados e escolher a melhor alternativa para tal.