Banco de Dados

13 set, 2013

Índices: Equilibrando os pratos da balança

Publicidade

Desde que inventaram os primeiros computadores, os profissionais da área de tecnologia da informação são pressionados a desenvolver aplicações em prazos cada vez menores.  Não por acaso, as ferramentas de desenvolvimento evoluíram absurdamente, dando mais poder para os programadores dominarem todas as etapas do processo de criação de aplicações e sistemas.

Mas esse poder tem um efeito colateral que nem sempre é avaliado com a atenção necessária. Se o programador passa a ter controle sobre mais e mais aspectos relacionados à criação dos sistemas, ele também recebe a responsabilidade e a obrigação de conhecer esses assuntos com maior profundidade.

Um desses aspectos é a criação dos bancos de dados. Cada vez mais vemos empresas nas quais a modelagem da base e a estratégia de indexação das tabelas são de responsabilidade de programadores. E essas tarefas são fundamentais para a boa operação de um banco de dados e, consequentemente, de toda aplicação.

Neste artigo, eu comento sobre algumas posturas em relação ao uso de índices e os erros mais comuns que são cometidos.

Perfis dos profissionais

Existem dois tipos de programadores que preocupam qualquer DBA: os otimistas, que acham que basta criar as tabelas e o banco de dados estará pronto; e os pessimistas, que têm medo de que a base tenha problemas com performance e resolvem tomar “providências” sobre o assunto por conta própria.

Veja a seguir os problemas que podem ocorrer com esses tipos de profissionais.

O programador otimista

Ser otimista demais dá muito trabalho para o SGBD. Criar as tabelas é só o primeiro passo na construção da base de dados. É sempre muito importante definir chaves primárias em todas as tabelas, as chaves estrangeiras correspondentes e, principalmente, os índices que serão usados.

Indexação é essencial para consulta dos dados. Você pode ter a falsa impressão de que é bom criar tabelas sem nenhum índice, já que isso vai ajudar seu banco de dados a ter uma performance um pouco melhor nas operações de alteração de dados (INSERT, DELETE, UPDATE). E esse efeito é real. Numa operação de inserção em uma tabela sem índices, por exemplo, a operação vai ser registrada no log do banco e em seguida o registro será gravado nas páginas de dados dessa tabela. E só.

Porém, você nunca na sua vida vai trabalhar com um banco de dados em que só se insere/altera dados. Todo banco de dados precisa ser bom na recuperação dos dados, ou seja, precisa ter boa performance em operações SELECT. Afinal, para que serviria gravar dados que nunca seriam lidos?

Em 99% dos casos, consultas filtram e/ou agrupam dados. E essas duas operações obrigam o SGBD a pesquisar por registros específicos. Se não houver nenhum índice na tabela, o SGBD terá que vasculhar todas as páginas de dados para localizar esses registros. É como procurar uma palavra dentro de um livro inteiro.

Um índice é um catálogo que funciona de forma muito parecida com aqueles índices remissivos que existem no final dos livros. Ali, o leitor pesquisa a palavra desejada e o índice mostra em que páginas ela é encontrada. E, grosseiramente, é assim que funciona o índice de uma tabela.

É fácil entender por que um índice pode ajudar muito a performance das consultas em uma tabela, e que a falta de índices (ou existência de índices ruins) causará um enorme impacto na performance. Eu não me lembro de nenhum cenário em que seja recomendável criar uma tabela sem nenhum índice. É obrigação do proprietário da tabela criar ao menos um índice, e ele deve ter muito cuidado na escolha dos campos que farão parte desse índice.

O programador pessimista

Outro comportamento desastroso é o do programador que não confia nos índices que ele definiu… e daí resolve criar um batalhão de índices em cada tabela. Vi muitas vezes profissionais tão pessimistas que até subestimaram a eficiência do otimizador de consultas do SGBD e definiram índices sobre as mesmas colunas, mudando apenas a ordem em que elas aparecem.

Índices são, grosso modo, resumos dos dados.  Assim sendo, é de se esperar que cada índice ocupe uma pequena fração do espaço ocupado pelos dados. É muito comum que se crie mais de um índice por tabela, mas é preciso ter muito cuidado com isso.

Eu já vi ambientes de produção em que havia tabelas com centenas de milhões de registros que tinham tantos índices diferentes que os dados representavam menos de 20% do espaço ocupado em disco… os outros 80% eram usados para armazenar índices!

Pense no impacto que isso causa para o banco de dados: cada novo registro que é inserido, atualizado ou excluído da tabela, precisa ser registrado primeiro no log do banco, depois nas páginas de dados da tabela e em seguida nas páginas de dados de cada um dos índices que estão associados à tabela.

Se sua tabela tiver seis índices, por exemplo, uma única operação de INSERT precisará escrever dados em oito lugares! Evidente que qualquer alteração de dados será muito lenta numa tabela com tantos índices.

E ainda existe um risco escondido nessa história. Você até pode imaginar que suas operações de SELECT terão garantia de boa performance…  Mas isso não é verdade.

A boa performance depende da qualidade dos índices que você definiu. Portanto, índices ruins certamente vão impactar a alteração de dados, mas eles podem não funcionar bem na seleção de dados.

Isso leva à outra questão: é preciso muito cuidado para definir os índices de cada tabela.

Bons índices

Um bom índice deve ter alta cardinalidade, isto é, usar valores que são raramente repetidos. Dessa forma, um valor pesquisado vai selecionar um pequeno número de registros (e muitas vezes um único registro, como acontece quando temos índices do tipo UNIQUE). Por exemplo: nunca se devem indexar campos do tipo SIM ou NÃO, já que eles selecionam metade de toda tabela.

Outra característica que se deve observar é o “comprimento” do índice, ou seja, a quantidade de campos e o tamanho dos campos usados no índice. Comprimento menor significa menos espaço para armazenamento do catálogo de dados e também maior facilidade de processamento pelo SGBD.

A relevância do índice em termos de negócio também deve ser observada. Muitas vezes, temos problemas com índices que são tecnicamente bons, mas que não são relevantes do ponto de vista do negócio e por isso não apresentam boa performance. Uma chave substituta (leia-se: campo IDENTITY ou SEQUENCE) é um ótimo candidato a índice, considerando-se os aspectos técnicos. Mas ela não representa nada no mundo dos negócios. Ela foi criada apenas para facilitar a identificação do registro da tabela.

Isso não quer dizer que chaves substitutas sejam sempre índices ruins. Existem muitos casos em que a chave candidata da tabela (aquela que identifica um registro e o torna único) é composta por oito ou mais colunas. Isso acontece, por exemplo, quando se trabalha com modelagem multidimensional (Business Intelligence).

Nesses casos, é muito provável que a chave candidata seja uma chave muito longa e, eventualmente, seria vantajoso indexar a chave substituta em vez da chave candidata. Essa é uma escolha arriscada e exige que o DBA e/ou programador avalie caso a caso a estratégia a ser usada.

O que são índices clusterizados

Por último, é preciso diferenciar dois tipos essenciais de índices. A grande maioria dos SGBDs relacionais usa ao menos dois tipos de índices que precisam ser conhecidos por todo profissional que lida com bancos de dados: os índices clusterizados e os não-clusterizados.

Em geral, quando falamos de um índice, estamos pensando no que chamamos de índices não-clusterizados. Estes são catálogos construídos a partir dos dados da tabela, nos mesmos moldes do índice remissivo dos livros que eu descrevi anteriormente. Cada tabela pode ter quantos índices não-clusterizados que se deseje criar.

Mas índices clusterizados funcionam de modo muito diferente. Em vez de criar um catálogo, esse índice redefine a ordenação física em que os dados são armazenados. Isso quer dizer que os dados são inseridos nas páginas de dados de tal maneira que sejam fisicamente gravados na ordem desejada. Por essa razão, cada tabela pode ter no máximo um índice clusterizado.

Por conta disso, todos os índices não-clusterizados de uma tabela criam catálogos baseados na ordenação definida pelo índice clusterizado (caso ele exista). Sendo assim, é fundamental que o índice clusterizado da tabela seja de boa qualidade, porque dele dependem todos os outros índices. Um bom índice clusterizado ajudará a melhorar performance dos índices não-clusterizados.

Manutenção de índices

Apenas criar índices não é uma solução definitiva. Índices se fragmentam à medida que os registros da tabela são inseridos ou alterados. E precisam de manutenção periódica, para que o catálogo (ou seja, as páginas de dados do índice) seja reorganizado. Essa é a famosa operação de REBUILD.

E também não se pode esquecer que o otimizador de consultas do SGBD decide pela utilização ou não de um dado índice em um determinada consulta baseando sua escolha nas estatísticas de utilização desse índice. São elas as estatísticas, que acabam por definir como será a interação entre o otimizador de consultas e os índices da tabela.

É muito importante que se criem estatísticas de uso de índices e que elas sejam recicladas quando necessário. Estatísticas desatualizadas podem induzir o otimizador de consultas a tomar decisões erradas, comprometendo a performance das consultas.

Conclusão

Indexação é de fundamental importância para o bom funcionamento de um banco de dados. Mas é um assunto complexo. É muito importante que o proprietário/administrador/desenvolvedor da base aja com bom senso na definição dos índices.

Do mesmo modo como o remédio que pode curar ou matar, dependendo da dose que se ingere, os índices podem ser a salvação ou o pesadelo do seu banco de dados. E o caminho para evitar problemas é consultar um especialista… e ler a bula (documentação) para conhecer melhor esse remédio.

***

Este artigo foi originalmente publicado na Revista iMasters – edição #07: http://issuu.com/imasters/docs/revista-imasters7