Archive | Maio, 2006

Optimização de aplicações MySQL – parte I

Acontece frequentemente não se pensar muito bem na estrutura de uma base de dados para um site aquando da criação da mesma. O que é certo é que, mais tarde ou mais cedo, dependendo do crescimento do site em termos de informação, os erros de estruturação da base de dados vão-se fazer notar. E normalmente, quando damos conta, temos em mãos um sério problema para resolver, com algumas implicações.

Aconteceu-me recentemente isto que acabei de descrever, e, na tentativa de optimizar estrutura da informação da base de dados em questão, procurei saber mais acerca da indexação da informação e da forma como o MySQL usa esta indexação.

Índices: o que são?

Os índices podem ser entendidos como o turbo do MySQL. São uma versão organizada de campos específicos de uma tabela e são usados para facilitar a consulta de registos. Sem índices, o MySQL necessita percorrer todos os registos de uma tabela para encontrar o registo pretendido, o que não acontece quando se usam índices. Neste caso, o MySQL consegue “saltar” directamente para o registo pretendido. Com o seu uso, as consultas de informação tornam-se mais rápidas e eficazes, poupando tempo de processamento.

Tipos de Índices

Existem vários tipos de índices disponíveis no MySQL:

  • Índices normais – são o tipo de índice mais básico, e não possuem restrições tais como a unicidade;
  • Índices únicos – semelhantes aos índices normais, mas com uma diferença: todos os valores do(s) campo(s) indexado(s) apenas podem aparecer uma vez;
  • Chaves primárias – índices únicos com nome “PRIMARY” e com a particularidade de apenas poder existir um por tabela;
  • Índices full-text – usados pelo MySQL para pesquisas em campos de texto (para não fugir ao tema, sugiro a leitura da documentação do MySQL para mais detalhes sobre este tipo de índices).

Definição de Índices

Os índices podem ser aplicados individualmente a campos de uma tabela da base de dados (índices simples), ou então aplicados a vários campos de uma tabela (índices compostos).

Suponhamos que temos a seguinte tabela:

CREATE TABLE pessoas (
    id INT NOT NULL AUTO_INCREMENT,
    primeiro_nome CHAR(30) NOT NULL,
    ultimo_nome CHAR(30) NOT NULL,
    idade SMALLINT NOT NULL,
    PRIMARY KEY (id)
);

O objectivo é usar esta tabela para obter os valores do campo id para registos cujos valores do primeiro nome, último nome e idade são conhecidos. Um exemplo de consulta seria pesquisar todos os registos com o nome Hugo Durães e 24 anos de idade:

SELECT id FROM pessoas WHERE primeiro_nome='Hugo' AND ultimo_nome='Durães' AND idade=24;

Como não queremos que o MySQL faça uma pesquisa em todos os registos da tabela, o uso de índices é altamente recomendado.

Na minha opinião, o primeiro passo seria criar um índice para um dos campos da claúsula WHERE (primeiro_nome, ultimo_nome ou idade). Se o índice fosse criado no campo primeiro_nome, o MySQL iria limitar a pesquisa aos registos para os quais o campo primeiro_nome fosse ‘Hugo’. Com este resultado temporário, iria aplicar as restantes condições: primeiro iria eliminar todos os registos cujo ultimo_nome fosse diferente de ‘Durães’ e de seguida eliminaria os registos nos quais a idade fosse diferente de 24. Só após isto o MySQL poderia devolver os resultados da consulta.

A criação deste índice torna a consulta mais eficiente, mas ainda obriga o MySQL a trabalhar com registos não necessários. Poderíamos colocar o índice em qualquer outro dos campos, mas os resultados em termos de eficiência seriam muito idênticos.

É aqui que entram os índices compostos. Um índice composto é na verdade um array ordenado que contém concatenados os diferentes valores dos campos que pertencem ao índice composto.

Assim, para o exemplo mostrado acima, seria criando um índice composto pelos campos primeiro_nome, ultimo_nome e idade. Desta forma, o MySQL pode “saltar” imediatamente para o primeiro_nome correcto, depois para o ultimo_nome e finalmente para a idade correcta. A informação foi assim encontrada sem ser necessário percorrer qualquer registo da tabela.

Mas não será a criação deste índice composto a mesma coisa que criar um índice para cada campo da claúsula WHERE? Não, porque ao executar uma consulta, o MySQL apenas usa um índice. Se tiver que existir uma escolha entre vários índices, o MySQL usa normalmente o índice mais restritivo, ou seja, o que devolve o menor número de registos. Ainda assim, qualquer um destes índices nunca é tão restritivo como o índice composto pelos três campos da claúsula WHERE.

Da esquerda para a direita

Os índices múltiplos tem uma vantagem acrescida: são lidos da esquerda para a direita. Assim, e usando o exemplo acima, o índice será usado para consultas de acordo com a seguinte combinação:

  • primeiro_nome, ultimo_nome, idade
  • primeiro_nome, ultimo_nome
  • primeiro_nome

Assim, o índice criado é usado nas seguintes consultas (alguns exemplos):

SELECT * FROM pessoas WHERE primeiro_nome='Hugo';

SELECT * FROM pessoas
  WHERE primeiro_nome='Hugo' AND ultimo_nome='Durães';

SELECT * FROM pessoas
  WHERE primeiro_nome='Hugo' AND ultimo_nome='Durães' AND idade=24;

SELECT * FROM pessoas
  WHERE primeiro_nome='Hugo'
  AND (ultimo_nome='Durães' OR ultimo_nome='Fernandes') AND idade=24;

SELECT * FROM pessoas
  WHERE primeiro_nome='Hugo'
  AND ultimo_nome='Durães' AND idade > 20 AND idade < 26;

No entanto, o índice criado não é usado nas seguintes consultas (alguns exemplos):

SELECT * FROM pessoas WHERE ultimo_nome='Durães';

SELECT * FROM pessoas
  WHERE primeiro_nome='Hugo' OR ultimo_nome='Durães';

SELECT * FROM pessoas
  WHERE idade=24 AND primeiro_nome='Hugo';

Em que campos devem ser criados índices?

Um dos passos mais importantes é a escolha dos campos onde criar os índices. Existem dois locais fulcrais para a criação de índices: campos referenciados na claúsula WHERE e campos usados na claúsula JOIN.

Então basta seguir a “regra” e criar índices em todos os campos que estejam nessas condições? Quase, mas nem sempre. É necessário ter em conta o tipo de comparações que vão ser efectuadas. O MySQL apenas usa índices para comparações do tipo < , <=, =, >, >=, BETWEEN, IN e em algumas do tipo LIKE. Nas comparações do tipo LIKE, o MySQL não usa índices caso o primeiro caracter de pesquisa seja uma wildcard (% ou _).

Desvantagens dos índices

É bastante comum, em aplicações web, existirem mais pedidos simultâneos de consultas do que pedidos de actualização de informação, visto que o número de pessoas a consultar uma aplicação deste tipo é, normalmente, bem maior que o número de pessoas que actualizam a informação. Assim, o ideal será dar prioridade a estas consultas, deixando para segundo plano as actualizações de informação.

A criação de índices, com vista a indexar a informação, resulta numa melhoraria das consultas de informação. Mas, em contrapartida, estamos a dificultar os pedidos de actualização de informação. Logo, a definição dos índices tem de ser bem estudada, de modo a que seja aplicada apenas sobre pontos críticos.

O uso de índices provoca um aumento do espaço ocupado em disco. Assim, a criação de índices não estudada pode provocar um aumento exagerado do tamanho da informação indexada, podendo esta chegar ao seu limite físico em termos de tamanho em disco.

Concluindo…

O uso de índices é um dos aspectos mais importantes para optimizar bases de dados. Não importa o quão simples é uma tabela: uma pesquisa numa tabela não indexada com 1.000.000 de registos nunca será rápida e leve.

Este artigo tentou abordar os aspectos mais importantes relativos ao tema. No entanto, se pretender saber mais, aconselho a consulta do tópico Optimizing Database Structure do manual do MySQL.

Agora quero ver o MySQL a correr “sem espinhas”! ;)

Artigos relacionados:
Optimização de aplicações MySQL – parte II

Não usar refresh para redireccionamentos

Se pretender que o endereço http://www.exemplo.com/foo mostre o conteúdo que está em http://www.exemplo.com/bar, não deve usar técnicas de “refresh” como:

<meta http-equiv=refresh content="1; url=http://www.exemplo.org/bar">

Porquê? Simplesmente porque desta forma a acção do botão “Voltar” do browser será anulada. Um utilizador, ao pressionar o botão “Voltar”, vai fazer com que o “refresh” funcione novamente e será novamente redireccionado para a frente. Provavelmente esta situação vai deixar o utilizador aborrecido o que pode causar que este deixe de visitar o site.

Usar redireccionamentos HTTP

Ao ser usada a meta-tag “refresh” para criar um redireccionamento, o que temos é uma instrucção específica dentro do documento web. Neste caso, espera-se que o browser descarregue a página, analise o seu conteúdo, encontre a instrucção “refresh”, espere o tempo necessário (que pode ser de 0 – imediatamente – até X segundos) e que proceda para o novo endereço.

Por outro lado, um redireccionamento HTTP funciona de uma forma mais directa pois é feito a um outro nível. O servidor, quando recebe um pedido de um documento e está configurado para efectuar o redireccionamento desse documento para outro endereço, responde ao browser indicando-lhe que procure o documento na sua nova localização.

O redireccionamento HTTP é também uma forma muito mais correcta para fazer redireccionamentos, já que, para além do novo endereço, fornece mais informação ao browser: fornece informação acerca do propósito e do tipo de redireccionamento, o que permite ao browser agir de forma diferente dependendo do tipo de redireccionamento. Os tipos de redireccionamentos HTTP são os redireccionamentos permanentes (HTTP 301), redireccionamentos temporários (HTTP 307) e os redireccionamentos indefinidos (HTTP 302).

Deixo alguns links úteis onde se mostra como efectuar a configuração de servidores para usar redireccionamentos HTTP:

Introdução às Cascading Style Sheets (CSS)

As CSS ou, em português, folhas de estilo, são um mecanismo simples para estilizar um documento web, trabalhando em conjunto com liguagens de marcação, como o XHTML, com a finalidade de lhes conferir o aspecto por nós desejado.
Neste trabalho conjunto, as linguagens de marcação definem a estrutura geral do documento web no que diz respeito a cabeçalhos, tabelas, formulários, etc., ficando ao cargo das CSS a formatação de detalhes como tipos, tamanhos e cores das letras, fundos do documento entre outras formatações semelhantes.

Basicamente, podemos dizer que são uma lista de regras, para uma página web ou site. Estas regras podem ser aplicadas a páginas inteiras ou apenas a tags específicas. Por exemplo:

<h1 class="centered">Exemplo</h1>
<p>Este é um texto para exemplo</p>

Como é possível visualizar no exemplo, o elemento “h1″ aparece centrado em relação ao ecrã.

Porquê o uso das CSS?

As CSS são o método mais correcto para estilizar conteúdos web pelas seguintes razões:

  • Permitem uma maior precisão em mudanças de formatação, na medida em que podem ser usadas para estilizar documentos ou tags únicas dentro de um documento;
  • Estando as regras de estilo todas definidas num único local, possibilita que alterações efectuadas a este ficheiro afectem todas as páginas onde estas regras são incluídas;
  • Muitos dos elementos tradicionais e atributos do XHTML, especialmente dedicados à formatação dos conteúdos, estão a deixar de ser suportados, ou seja, estão a tornar-se “deprecated”.

Estrutura das CSS

Nas CSS, cada regra é composta por um selector, que indica onde vai ser aplicado o estilo definido pela regra, e por um conjunto de pares propriedade/valor que define o estilo. O formato básico é o seguinte:

selector { propriedade1: valor1; propriedade2: valor2; }

É visível no exemplo acima que o conjunto de pares de propriedades/valores está entre “{” e “}” — chavetas — e que os pares estão separados por ponto-e-vírgula “;”. Cada par propriedade/valor é separado por dois pontos “:”.

h1 { color: #000000; font-size: 105%; }

Neste último exemplo, o selector é o “h1″, que é o elemento XHTML para um cabeçalho de primeiro nível. O primeiro par propriedade/valor confere a cor preta ao cabeçalho (o código hexadecimal #000000 representa a cor preta). O segundo par dá ao cabeçalho um tamanho 5% maior que o tamanho normal para o texto.

Usando DIV e SPAN para aplicar CSS

Dois elementos muito úteis quando se trabalha com CSS são os elementos “div” e “span”, que podem ser vistos como tags “invisíveis”, já que quando usadas por si só têm pouco significado. No entanto, quando combinadas com regras de estilo, podem ser usadas como “contentores” para aplicar estilos.

No caso de querermos realçar uma palavra poderiamos usar o seguinte:

...uma <span class="negrito">palavra</span> poderiamos...

A definição da regra de estilo para este exemplo seria:

.negrito{ font-weight: bold; }

Para aplicar esta mesma regra a uma secção inteira de um documento poderiamos usar o seguinte:

<div class="negrito">
<h1>Exemplo</h1>
<p>Parágrafo 1...</p>
<p>Parágrafo 2...</p>
<p>Parágrafo 3...</p>
</div>

Há que ter em atenção que caso se definam estilos para os elementos “h1″ e “p”, estes irão sobrepor-se ao estilo definido pela regra “negrito”.

Formas de especificar as CSS

Para aplicar uma CSS a um documento XHTML, é necessário especificar as regras de estilo e de alguma forma associá-las ao documento, de forma a que os conteúdos assumam os estilos definidos.

A CSS pode ser especificada de três formas:

  • Style Sheets Externas – Estas regras de estilo são guardadas num documento separado e incluídas no nosso documento XHTML. O código seguinte deve ser colocado entre as tags head:

<link rel="stylesheet" type="text/css" href="style.css" />

  • Style Sheets Internas – Ao contrário das Style Sheets Externas, as internas são definidas no próprio documento, ficando apenas disponíveis nesse documento, sendo por isso impossível serem referenciadas por outros documentos. O código seguinte deve ser colocado entre as tags head:

<style type="text/css">
<!--
.exemplo { width: 90%; background-color: #CCCCCC; }
-->
</style>

  • Inline Styles – As regras são aplicadas directamente a um elemento XHTML. Esta forma de especificar as regras de estilo é a menos eficiente, visto que é impossível reutilizar estas regras como nos dois primeiros casos. Para além disso, esta forma de especificar as regras de estilo torna difícil possíveis alterações futuras ao aspecto geral de um site, já que obriga a verificar cada elemento nos quais são necessárias alterações.

<span style="color: #000000;">texto</span>

Como interagem entre si?

Depois de saber as três formas de aplicar estilos a um documento, é importante saber como é que estas três formas interagem entre si.

As CSS funcionam como uma hierarquia – estilos aplicados de uma forma geral para os aplicados de forma mais específica. Podemos dizer que as regras incluídas num documento afectam todo um documento ou mesmo todo um site (estilos aplicados de uma forma geral), mas que as regras aplicadas directamente num elemento apenas afectam esse elemento (estilos aplicados de uma forma específica).

Assim, se dois estilos podem ser aplicados ao mesmo elemento, é dada prioridade às regras aplicadas de forma específica, ou seja, se de uma forma geral for especificado que o texto de um site será vermelho, mas especificamente for especificado que este será azul, a cor mostrada será o azul.

Paralelamente a isto, existe também a existência de herança entre estilos, ou seja, se de uma forma geral for especificado que o texto de um site será azul, mas se especificamente for especificado que este será negrito, o texto irá ser mostrado com a cor azul e a negrito.

Concluindo…

Entre as diferentes formas de especificar a CSS a usar num site, recomenda-se o uso de style sheets externas. Desta forma conseguem-se centralizar num só local todas as regras de estilo, o que torna muito mais simples eventuais alterações que possam surgir aos estilos do site. Para além disto, estando as regras centralizadas num só local, o carregamento de um site é bastante mais rápido e leve, já que os browsers apenas lêem a CSS na primeira vez que o site é carregado, ficando depois guardada em cache, o que liberta o servidor web de um processamento mais pesado.