O que é o PostgreSQL e por que startups dependem dele
O PostgreSQL é um banco de dados relacional open source com mais de 35 anos de desenvolvimento ativo. É robusto, extensível e suporta desde JSON até tipos geoespaciais. Por isso, virou a escolha padrão de startups que querem um banco sério sem pagar por Oracle ou SQL Server.
O problema é que PostgreSQL é poderoso e, justamente por isso, tem muitas alavancas. Mexer na alavanca errada em produção pode derrubar tudo. Startups costumam crescer rápido e o banco que funcionava bem com 10 mil registros começa a travar com 10 milhões.
Este guia cobre os pontos críticos que separam um banco saudável em produção de um banco que vira alerta às 3 da manhã. Não é teoria: são situações reais que aparecem quando a startup começa a escalar.
Como o PostgreSQL funciona por dentro
Entender o básico da arquitetura ajuda a tomar decisões melhores. O Postgres usa um modelo de MVCC (Multi-Version Concurrency Control): quando você atualiza uma linha, ele não apaga a versão antiga imediatamente. Cria uma nova versão e marca a antiga como "morta". Isso permite leituras concorrentes sem locks, mas gera acumulo de dados mortos chamados de dead tuples.
O processo AUTOVACUUM é responsável por limpar esses dados mortos periodicamente. Se ele não rodar com frequência suficiente (ou for desativado por engano), a tabela cresce desnecessariamente e as queries ficam mais lentas com o tempo.
Outro ponto importante: o Postgres usa um buffer pool na memória para cachear páginas de dados. Quanto mais RAM você der ao parâmetro shared_buffers, menos I/O de disco acontece. A regra geral é alocar cerca de 25% da RAM disponível para esse parâmetro em servidores dedicados.
Principais armadilhas em produção
Startups repetem os mesmos erros com PostgreSQL. Conhecer esses padrões economiza horas de depuração:
- Falta de índices nas colunas de filtro: queries com WHERE em colunas sem índice fazem full table scan. Com milhões de registros, isso trava tudo.
- Connection pooling ausente: cada conexão nova ao Postgres custa memória e CPU. Sem um pooler como o PgBouncer, aplicações que abrem muitas conexões simultâneas esgotam os recursos.
- Backups não testados: fazer backup sem nunca testar o restore é o mesmo que não ter backup. O restore real precisa ser validado periodicamente.
- Migrations sem cuidado em produção: um
ALTER TABLE ADD COLUMN NOT NULLsem default em tabela grande pode bloquear todas as operações por minutos. - Autovacuum mal configurado: tabelas com muitos updates (como filas de jobs) acumulam dead tuples se o autovacuum não for ajustado para rodar mais agressivamente.
Nunca rode VACUUM FULL em tabelas grandes durante horário de pico. Ele adquire lock exclusivo e bloqueia todas as operações na tabela enquanto roda.
Como começar: configuração mínima segura
Se você está subindo um Postgres novo para produção, faça isso antes de colocar carga real:
Passo 1 - Ajuste o PostgreSQL.conf básico:
shared_buffers = 256MB # 25% da RAM disponível
work_mem = 4MB # por operação de sort/hash
maintenance_work_mem = 64MB # para VACUUM e CREATE ÍNDEX
max_connections = 100 # ajuste conforme sua app
autovacuum = on # nunca desative issoPasso 2 - Instale o PgBouncer para connection pooling:
sudo apt install pgbouncer
# configure /etc/pgbouncer/pgbouncer.ini
# pool_mode = transaction (mais eficiente para a maioria dos casos)Passo 3 - Configure backups automáticos com pg_dump ou WAL-G:
# Backup simples diário com pg_dump
0 2 * * * pg_dump -U postgres meu_banco | gzip > /backups/$(date +%Y%m%d).sql.gzPasso 4 - Habilite a extensão pg_stat_statements para monitorar queries lentas:
-- no PostgreSQL.conf:
shared_preload_libraries = 'pg_stat_statements'
-- no banco:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- para ver as queries mais lentas:
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;Exemplo prático: encontrando e corrigindo uma query lenta
Cenário comum: a tela de listagem de pedidos da sua startup começa a demorar 8 segundos para carregar. O banco tem 2 milhões de registros na tabela orders.
Primeiro, use o EXPLAIN ANALYZE para entender o que o banco está fazendo:
EXPLAIN ANALYZE
SELECT * FROM orders
WHERE user_id = 12345
AND status = 'pending'
ORDER BY created_at DESC
LIMIT 20;Se o resultado mostrar Seq Scan em vez de Índex Scan, o banco está lendo a tabela inteira. A solução é criar um índice composto nas colunas do filtro:
-- Crie o índice de forma concorrente para não bloquear a tabela
CREATE ÍNDEX CONCURRENTLY idx_orders_user_status
ON orders (user_id, status, created_at DESC);Após criar o índice, rode o EXPLAIN ANALYZE de novo. O plano deve mudar para Índex Scan e a query vai de 8 segundos para menos de 100ms na maioria dos casos.
Sempre use CREATE ÍNDEX CONCURRENTLY em produção. Ele demora um pouco mais para criar, mas não bloqueia operações na tabela enquanto roda.
Comparação com alternativas
PostgreSQL não é o único banco relacional. Entender quando usar cada um ajuda a tomar a decisão certa:
MySQL/MariaDB: mais simples de configurar, amplamente suportado em hospedagens compartilhadas. Perde para o Postgres em tipos avançados (JSON nativo, arrays, ranges) e em conformidade com o padrão SQL. Boa escolha para apps simples que precisam de hospedagem barata.
SQLite: excelente para desenvolvimento local, apps mobile e projetos pequenos. Não suporta múltiplas conexões simultâneas de escrita. Não é opção para produção com múltiplos usuários concorrentes.
MongoDB: banco de documentos, sem esquema fixo. Útil quando os dados são realmente não estruturados. O Postgres com JSONB resolve a maioria dos casos de uso do Mongo com a vantagem de ter transações ACID e joins reais.
Para a maioria das startups, PostgreSQL é a escolha certa desde o início: você não vai precisar migrar quando crescer.
Pontos positivos e limitações
Pontos positivos:
- Open source e gratuito, sem licenciamento por núcleo ou usuário
- ACID completo: transações confiáveis mesmo em caso de falha
- Tipos avançados: JSONB, arrays, UUID, tipos geométricos, full-text search nativo
- Extensível: PostGIS para geodados, TimescaleDB para séries temporais, pgvector para IA
- Comunidade enorme, documentação excelente
Limitações reais:
- Escala vertical mais facilmente do que horizontal. Sharding é complexo.
- Configuração padrão é conservadora: precisa de tuning para produção de verdade
- Replicação e failover automático exigem ferramentas extras (Patroni, repmgr)
- Não é a melhor escolha para workloads 100% analíticos pesados: aí o BigQuery ou Redshift ganham
O PostgreSQL padrão não tem failover automático. Se o servidor cair, alguém precisa promover a réplica manualmente. Considere Patroni ou um serviço gerenciado (RDS, Supabase, Néon) se alta disponibilidade for crítica.
Casos de uso reais
SaaS B2B com múltiplos clientes: cada cliente tem seus dados isolados por tenant_id. O Postgres lida bem com Row Level Security para garantir isolamento sem criar um banco por cliente.
E-commerce com catálogo variado: produtos com atributos diferentes (eletrónicos vs. roupas) ficam bem em JSONB. Você tem esquema fixo nas colunas principais e flexibilidade nos atributos.
Sistema financeiro: transações ACID garantem que um débito sempre tem um crédito correspondente, mesmo em caso de falha no meio da operação.
API com busca textual: o tsvector e tsquery do Postgres oferecem full-text search razoável sem precisar de Elasticsearch para casos simples.
Dicas e boas práticas
Ative a extensão pg_stat_statements logo no primeiro dia. Ela registra todas as queries executadas e é a melhor ferramenta para encontrar gargalos depois.
Use EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) para ver não só o plano de execução, mas também quantas páginas foram lidas do cache vs. do disco. Alto número de shared_read indica que o shared_buffers está pequeno.
Nunca use SELECT * em tabelas grandes em produção. Buscar todas as colunas aumenta o tráfego de rede e impede que o banco use índex-only scans. Sempre especifique as colunas que você precisa.
Para migrations em produção em tabelas grandes, prefira adicionar colunas com valor NULL e depois fazer o backfill em lotes pequenos. Adicionar coluna NOT NULL sem default bloqueia a tabela inteira durante a migration.
Vale a pena?
Para startups, a resposta é quase sempre sim. O PostgreSQL é gratuito, tem suporte excelente em todos os provedores de cloud (AWS RDS, Google Cloud SQL, Azure Database, Supabase, Néon) e escala bem até o ponto em que você vai precisar de uma equipe de DBA dedicada de qualquer jeito.
O investimento real não é no banco em si, mas em aprender a operá-lo corretamente. Dedicar alguns dias para entender índices, autovacuum e connection pooling vai salvar muitas noites de incidente.
Se você ainda está no início, comece com um serviço gerenciado como o Supabase ou o Néon: eles cuidam de backups, failover e atualizações enquanto você foca no produto. Quando crescer o suficiente para justificar, migra para uma instância gerenciada no seu cloud provider.
Comentários
Deixar um comentárioVocê precisa ter uma conta no DevLevelUp para comentar.