Índices são, sem dúvida, um jeito massa de turbinar seu banco de dados, mas como dizem por aí, “o ótimo é inimigo do bom”. Nem todo índice é útil, e quando tem índice demais, pode mais atrapalhar do que ajudar. Parece estranho, mas é isso mesmo. Bora entender melhor.
Imagina uma biblioteca gigante, onde pra achar os livros tem vários catálogos — tipo por autor, por gênero, por ano de publicação. Cada catálogo desses ajuda a encontrar o livro rapidinho. Mas se tiver catálogo demais — tipo pra cada palavra do título ou cada detalhe — ao invés de ajudar, vira bagunça: demora mais pra achar, ocupa espaço pra caramba, e o bibliotecário tem que ficar atualizando tudo o tempo todo.
No banco de dados, os índices funcionam mais ou menos assim: eles ajudam a achar os dados rápido, mas se tiver índice demais, atualizar tudo quando adiciona ou muda um registro vira um perrengue. E o espaço em disco também sofre. Fora que, com índice demais, o sistema pode até se confundir sobre qual usar.
Então, igual aos catálogos da biblioteca, com índices é melhor não exagerar — é melhor ter poucos e bons do que um monte inútil.
Bora brincar de "detetive do PostgreSQL". Imagina que você criou três índices pra uma coluna só. Fez isso achando que ia melhorar a performance. Mas olha só:
- Se sua tabela é uma lista grandona de estudantes e tem três índices, cada vez que você adiciona um estudante, vai rolar três atualizações de índice. Não parece que ficou mais rápido, né?
- E se você tem 10 tabelas dessas, cada uma cheia de índice? A performance do banco inteiro vai pro saco.
Como saber se você tá com indexação demais?
A primeira coisa pra descobrir se tem problema é olhar os índices que já existem. No PostgreSQL, dá pra ver isso com o comando:
\d nome_da_tabela
Esse comando mostra a tabela, as colunas e os índices ligados nela. Se você ver um monte de índice numa tabela só, já é motivo pra desconfiar.
Outro truque massa é usar a view do sistema pg_stat_user_indexes. Ela mostra o quanto os índices são usados, então dá pra sacar se tem índice “peso morto”:
SELECT
relname AS table_name,
indexrelname AS index_name,
idx_scan AS index_scans
FROM
pg_stat_user_indexes
WHERE
idx_scan = 0;
Se idx_scan for 0, quer dizer que o índice nunca foi usado nas queries. Esse aí é candidato forte pra ser deletado.
Exemplo de indexação excessiva
Imagina uma tabela de usuários:
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE,
username VARCHAR(50),
created_at TIMESTAMP DEFAULT NOW()
);
E a gente tem três índices:
-- Índice em email
CREATE INDEX idx_users_email ON users (email);
-- Índice em username
CREATE INDEX idx_users_username ON users (username);
-- Índice em created_at
CREATE INDEX idx_users_created_at ON users (created_at);
Agora bora ver os tipos de query que a gente faz normalmente:
- Buscar usuário pelo email.
- Buscar usuário pelo username.
- Ordenar usuários por
created_at.
Parece que os índices são úteis. Mas olha o detalhe: se essas queries são raras (tipo, uma vez por semana), criar índice não vale a pena. E se alguns desses índices nunca são usados, eles só vão pesar nas operações de insert e update.
Pra ilustrar: imagina que temos esses dados na tabela users:
| user_id | username | created_at | |
|---|---|---|---|
| 1 | alex.lin@mail.com | alexlin | 2024-06-15 10:23:00 |
| 2 | anna.min@mail.com | annamin | 2024-06-16 12:47:00 |
| 3 | otto.song@mail.com | ottosong | 2024-06-17 08:30:00 |
| 4 | maria.chi@mail.com | mariachi | 2024-06-18 14:10:00 |
Se quase nunca rola busca por username, o índice idx_users_username nunca é usado (idx_scan = 0) e pode ser removido pra otimizar.
Ou seja, índice é uma ferramenta top, mas tem que usar com cabeça. Melhor ter poucos e bem usados do que um monte sobrando.
Como evitar indexação demais
- Analise os índices usados. Como já falamos, dá uma olhada na estatística de uso dos índices com
pg_stat_user_indexes. Se o índice quase não é usado, provavelmente pode ser removido:
DROP INDEX IF EXISTS nome_do_índice;
- Crie índices só pros queries que você usa muito. Antes de criar um índice, se pergunte:
- Essa coluna aparece muito em
WHERE,ORDER BY,GROUP BY? - A tabela tem muitos dados?
- A query realmente fica lenta sem índice?
Se a resposta for "não" pra qualquer uma dessas, talvez nem precise criar o índice.
- Use índices compostos. Se você sempre usa várias colunas juntas numa query, ao invés de criar um índice pra cada, faz um composto:
CREATE INDEX idx_users_email_username ON users (email, username);
Isso acelera queries que filtram por email e username ao mesmo tempo.
- Revise seus índices de tempos em tempos. Com o crescimento do banco, suas queries podem mudar. O que era útil ano passado pode ser inútil hoje. Então, revisa seus índices de vez em quando e apaga os que não servem mais.
Minimizando índices na prática
Bora voltar pra nossa tabela users. Ao invés de três índices separados, dá pra otimizar assim:
- Tira o índice de
created_atse quase nunca rola ordenação por ele. - Ao invés de dois índices separados pra
emaileusername, faz um composto:
CREATE INDEX idx_users_email_username ON users (email, username);
Resumo: qual é o segredo do equilíbrio?
Como em muita coisa de programação, aqui vale o minimalismo: "Menos é mais". Não precisa indexar toda coluna só porque dá. Pensa bem pra que serve o índice e se ele realmente vai melhorar a performance. Seja pragmático e lembra: dev bom não é quem sai criando índice pra tudo, mas quem entende o impacto e usa do jeito certo.
Agora, com essa ferramenta na mão, você já pode evitar o desastre da indexação excessiva e deixar seu banco de dados voando igual guepardo, e não arrastando igual tartaruga carregando índice inútil.
GO TO FULL VERSION