Fundamentos10 min

Bancos de dados como gargalo: o suspeito usual

O banco de dados é frequentemente o primeiro suspeito em problemas de performance. Aprenda a identificar e resolver gargalos de banco.

Quando um sistema fica lento, o banco de dados é quase sempre o primeiro suspeito — e frequentemente é culpado. Bancos de dados são pontos de centralização: todas as requisições eventualmente convergem para eles.

Este artigo explora os gargalos mais comuns em bancos de dados, como identificá-los, e estratégias para resolvê-los.

O banco de dados é o coração do sistema. Quando ele sofre, tudo sofre.

Por que Bancos São Gargalos Frequentes

Centralização

Enquanto aplicações escalam horizontalmente com facilidade, bancos de dados tradicionais são mais difíceis de escalar.

100 instâncias de aplicação
         ↓
    1 banco de dados
         ↓
      Gargalo

Estado compartilhado

Diferente de aplicações stateless, bancos mantêm estado que precisa ser consistente — isso limita paralelismo.

I/O intensivo

Bancos fazem muito I/O de disco, que é ordens de magnitude mais lento que operações em memória.

Tipos de Gargalos

1. Queries lentas

A causa mais comum. Uma única query mal escrita pode derrubar o sistema.

Sintomas:

  • Latência alta em operações específicas
  • CPU do banco alta
  • Locks de longa duração

Causas:

  • Falta de índices
  • Índices não utilizados
  • Full table scans
  • Joins ineficientes
  • N+1 queries

2. Conexões esgotadas

Pool de conexões no limite.

Sintomas:

  • Timeouts de conexão
  • Aplicação "trava" esperando conexão
  • Conexões idle no banco

Causas:

  • Pool subdimensionado
  • Queries lentas segurando conexões
  • Connection leaks
  • Transações longas

3. Locks e contenção

Transações disputando os mesmos dados.

Sintomas:

  • Latência errática
  • Deadlocks
  • Transações abortadas

Causas:

  • Transações longas
  • Updates em linhas "quentes"
  • Falta de índices causando locks de tabela

4. I/O de disco

Disco não consegue acompanhar a demanda.

Sintomas:

  • I/O wait alto
  • Queries lentas mesmo com bons índices
  • Buffer pool thrashing

Causas:

  • Dados maiores que memória disponível
  • Muitas escritas
  • Disco subdimensionado

5. Replicação atrasada

Réplicas não acompanham o primário.

Sintomas:

  • Lag de replicação crescente
  • Leituras inconsistentes
  • Réplicas caindo

Causas:

  • Volume de escrita muito alto
  • Rede lenta entre primário e réplica
  • Réplica subdimensionada

Identificando o Gargalo

Métricas essenciais

Métrica O que indica
Query time (p95, p99) Queries lentas
Connections used/available Pressão de conexão
Lock wait time Contenção
Buffer hit ratio Eficiência de cache
Disk I/O wait Pressão de disco
Replication lag Atraso de réplicas

Ferramentas

PostgreSQL:

  • pg_stat_statements — queries mais lentas
  • pg_stat_activity — conexões ativas
  • pg_locks — locks ativos
  • EXPLAIN ANALYZE — plano de execução

MySQL:

  • slow_query_log — queries lentas
  • SHOW PROCESSLIST — conexões ativas
  • SHOW ENGINE INNODB STATUS — estado interno
  • EXPLAIN — plano de execução

A query mais importante

-- PostgreSQL: Top queries por tempo total
SELECT query, calls, total_time, mean_time
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 20;

O impacto de uma query = frequência × tempo médio.

Soluções

Para queries lentas

1. Adicione índices

-- Antes: full table scan
SELECT * FROM orders WHERE customer_id = 123;

-- Depois: index scan
CREATE INDEX idx_orders_customer ON orders(customer_id);

2. Reescreva queries

-- Antes: N+1
for order in orders:
    customer = query("SELECT * FROM customers WHERE id = ?", order.customer_id)

-- Depois: JOIN
SELECT o.*, c.*
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.date > '2024-01-01';

3. Desnormalize quando necessário

Adicione dados redundantes para evitar joins caros.

4. Particione tabelas grandes

CREATE TABLE orders (
    id SERIAL,
    created_at TIMESTAMP,
    ...
) PARTITION BY RANGE (created_at);

Para conexões

1. Dimensione o pool corretamente

connections = (cores * 2) + spindles

Onde spindles = número de discos.

2. Use connection poolers

  • PgBouncer (PostgreSQL)
  • ProxySQL (MySQL)

3. Encontre e corrija leaks

Monitore conexões que não retornam ao pool.

Para contenção

1. Transações curtas

-- Evite
BEGIN;
-- ... operações demoradas ...
-- ... processamento em código ...
COMMIT;

-- Prefira
-- Processe dados antes
BEGIN;
-- Apenas operações de banco, rápidas
COMMIT;

2. Ordene acessos

Sempre acesse tabelas/linhas na mesma ordem para evitar deadlocks.

3. Use SKIP LOCKED para filas

SELECT * FROM jobs
WHERE status = 'pending'
ORDER BY created_at
LIMIT 1
FOR UPDATE SKIP LOCKED;

Para I/O

1. Aumente memória (buffer pool)

Mais dados em cache = menos I/O.

2. Use SSDs

Diferença de 100x em latência comparado a HDDs.

3. Separe dados por temperatura

Dados quentes em storage rápido, dados frios em storage barato.

Para escala

1. Read replicas

Distribua leituras entre réplicas.

Escrita → Primário
Leitura → Réplicas (load balanced)

2. Sharding

Divida dados entre múltiplos bancos.

customer_id % 4 = shard_number

3. CQRS

Separe modelo de leitura do modelo de escrita.

Boas Práticas

Desenvolvimento

  1. Sempre use EXPLAIN antes de ir para produção
  2. **Evite SELECT *** — busque apenas colunas necessárias
  3. Pagine resultados — LIMIT e OFFSET ou cursor
  4. Use prepared statements — cache de planos de execução
  5. Monitore N+1 — ORM pode esconder queries ruins

Operação

  1. Monitore continuamente — queries que eram rápidas podem ficar lentas
  2. Mantenha estatísticas atualizadas — ANALYZE regularmente
  3. Planeje manutenção — VACUUM, reindex, etc.
  4. Teste com dados realistas — produção tem mais dados que dev
  5. Tenha alertas de slow query — seja proativo

Conclusão

Bancos de dados são frequentemente gargalos porque:

  • Centralizam acesso a dados
  • São difíceis de escalar horizontalmente
  • Dependem de I/O, que é lento

Para evitar problemas:

  1. Escreva queries eficientes — índices, joins otimizados
  2. Dimensione recursos adequadamente — conexões, memória
  3. Monitore proativamente — encontre problemas antes dos usuários
  4. Planeje para escala — réplicas, sharding, cache

Trate seu banco de dados como um recurso precioso. Cada query tem um custo.

banco de dadosSQLgargalosqueries
Compartilhar:
Read in English

Quer entender os limites da sua plataforma?

Entre em contato para uma avaliação de performance.

Fale Conosco