Operar em uma instância minimalista do Postgres com dois núcleos: insights sobre otimização de consultas

Operar toda uma empresa em uma pequena instância PostgreSQL de dois núcleos provoca um debate mais amplo sobre onde colocar a complexidade: em um bom design de consultas e na otimização do schema, ou simplesmente comprando mais capacidade de banco. Comentaristas discutem levar lógica e joins para a camada de aplicação versus manter regras de negócio e integridade dos dados no banco, abordando manutenibilidade, desempenho e garantias ACID. Muitos veem a alfabetização básica em SQL, indexação e análise de planos de consulta como subutilizada, enquanto outros ressaltam que o tempo do desenvolvedor e o product-market fit muitas vezes importam mais do que espremer até a última gota de eficiência do banco.

Viabilidade de instâncias minúsculas do Postgres

  • Muitos comentaristas apreciam o lembrete de que hardware modesto (2 núcleos, alguns GB de RAM) pode lidar com cargas de trabalho sérias, ecoando “há 20 anos fazíamos muito com bem menos”.
  • Alguns executam apps inteiros em VMs muito pequenas ou hosts ARM baratos e relatam bons TPS/RPS com design cuidadoso e cache.
  • Outros argumentam que, embora inspirador, isso pode ser exagero quando instâncias na nuvem são relativamente baratas para ampliar.

Deslocando a lógica do banco de dados para a aplicação

  • A frase do artigo “mova a lógica para a aplicação” é debatida.
  • Críticos dizem que mover joins/filtros para o app frequentemente aumenta o I/O de rede, as idas e voltas e a complexidade, além de desperdiçar os pontos fortes do banco.
  • Defensores observam casos em que:
    • Recursos do app escalam mais barato do que recursos do banco.
    • Parâmetros opcionais ou condições complexas são mais fáceis de lidar com várias consultas direcionadas do que com uma única consulta enorme que “faz tudo”.
    • Dividir joins de “pointer-chasing” em várias consultas indexadas pode tornar os sistemas mais “NoSQL-ready” e mais fáceis de cachear.

Lógica de negócio no banco vs no código

  • Um grupo prefere uso intenso de stored procedures e constraints, para que a lógica crítica seja ACID, centralizada e consistente.
  • Outro grupo prefere um “DB burro”:
    • Cargas de trabalho mistas de computação + dados são mais difíceis de perfilar e ajustar.
    • Ecossistemas e ferramentas de linguagem do banco (estilo PL/SQL) são vistos como mais fracos, mais difíceis de testar, versionar e documentar.
  • A discordância gira em torno de manutenibilidade vs forte integridade de dados, e não apenas desempenho.

Planejamento de consultas, joins e índices

  • Comentaristas questionam a ideia de que métodos de join como nested loop/hash/merge sejam “subótimos” em geral; isso depende do contexto.
  • O planejador baseado em custo do Postgres pode escolher ordens de join ruins, especialmente com estatísticas ruins ou muitos joins; a falta de hints explícitos de join frustra alguns.
  • Workarounds mencionados: ajustar work_mem, join_collapse_limit, desativar tipos de join (enable_*), usar WITH MATERIALIZED e entender as estatísticas das tabelas.
  • Há amplo consenso de que entender SQL, planos de consulta e indexação é cada vez mais raro, mas crucial.

Trade-offs de custo e otimização

  • Um lado: o tempo do desenvolvedor é muito mais caro do que alguns núcleos extras ou mais RAM; sobreotimizar para economizar alguns milhares por ano é economia de centavos, desperdício de libras.
  • O outro lado: a cultura de “é só adicionar hardware/cloud” leva a contas recorrentes enormes; tuning básico de consultas e design de schema deveria ser prática padrão.
  • Vários reforçam que atenção modesta e contínua ao desempenho evita crises posteriores e correria de SRE.