anúncios

Mostrando postagens com marcador noSQL. Mostrar todas as postagens
Mostrando postagens com marcador noSQL. Mostrar todas as postagens

quarta-feira, 14 de outubro de 2026

Como resolver gargalos no Banco de Dados sem romper o domínio

Em arquiteturas de microsserviços e sistemas de alta escala, um dos gargalos mais comuns surge no banco de dados. O padrão de projeto tradicional, focado em CRUD (Create, Read, Update, Delete), utiliza a mesma estrutura e as mesmas tabelas tanto para gravar dados quanto para consultá-los.

Conforme a aplicação cresce, essa abordagem unificada começa a dar sinais de cansaço: consultas analíticas com múltiplos JOINs pesados disputam recursos com inserções e atualizações críticas, gerando contenção de locks, alta latência e degradação geral de performance.

Para resolver esse problema estrutural, o padrão CQRS (Command Query Responsibility Segregation) propõe uma mudança fundamental de mentalidade. Neste artigo, é explicado os principais insights do "O guia completo de CQRS em como resolver gargalos no banco de dados".

O problema do modelo único (CRUD Tradicional)

No modelo tradicional, o mesmo modelo de dados serve a dois propósitos conflitantes:

  1. Escrita: Requer validação rígida de regras de negócio, dados normalizados (3NF) para evitar redundância e garantir consistência transacional (ACID).
  2. Leitura: Requer dados estruturados de forma simples, prontos para exibição na tela (UI/API), idealmente desnormalizados para evitar cruzamentos de tabelas dispendiosos.

Quando tentamos otimizar uma tabela para leitura (criando múltiplos índices, por exemplo), prejudicamos o desempenho das escritas. Quando otimizamos para escrita (normalizando excessivamente), tornamos as consultas lentas.

O Conceito de CQRS

O CQRS separa a aplicação em duas responsabilidades distintas:

1. Commands (Comandos / Escrita)

Objetivo: Alterar o estado do sistema (CriarPedido, AlterarEndereco).

Característica: Focado no domínio e na integridade das regras de negócio. Retorna apenas status de sucesso/falha, nunca o payload completo de dados.

Modelo de Dados: Normalizado e otimizado para gravações rápidas e consistentes.

2. Queries (Consultas / Leitura)

Objetivo: Retornar dados otimizados para apresentação.

Característica: Não altera o estado do sistema e não executa regras de negócio complexas.

Modelo de Dados: Desnormalizado, pré-formatado ou materializado exatamente na estrutura que o cliente (Front-end/Mobile) precisa consumir.

Principais Benefícios Arquiteturais

Benefício Descrição
Escalabilidade Independente Você pode escalar a infraestrutura de leitura (ex: réplicas de leitura, instâncias de cache ou NoSQL) de forma totalmente independente da base de escrita.
Alta Performance nas Consultas Elimina a necessidade de JOINs complexos em tempo de execução, pois os dados de leitura já estão projetados e prontos no banco de consultas.
Código de Domínio Mais Limpo O lado de escrita fica limpo de código referente a paginação, buscas avançadas e formatações para telas.
Segurança e Isolamento Permite conceder permissões diferenciadas em nível de infraestrutura para operações de leitura e escrita.

Cuidados e Armadilhas: Quando NÃO usar

Embora seja um padrão poderoso, o CQRS introduz complexidade acidental se aplicado no contexto errado.

Regra de ouro: Não utilize CQRS para aplicações simples, CRUDs convencionais ou domínios onde o volume de leituras e escritas seja baixo e equilibrado.

Principais desafios ao adotar CQRS:

  1. Consistência Eventual (Eventual Consistency): Se o modelo de leitura for atualizado de forma assíncrona (via mensageria e eventos de domínio), haverá um pequeno intervalo de latência até que o dado gravado no lado de escrita reflita na base de consulta.
  2. Duplicação de Código e Infraestrutura: Exige manter dois modelos distintos e, eventualmente, duas bases de dados diferentes (ex: PostgreSQL para escrita e MongoDB/Elasticsearch para leitura).
  3. Sincronização de Dados: É necessário implementar e monitorar mecanismos tolerantes a falhas para garantir que os eventos de atualização cheguem à base de leitura.

Exemplo Prático de Código

Abaixo apresentamos um exemplo conceitual em TypeScript demonstrando a separação das responsabilidades de escrita (Command) e leitura (Query):

// Command Handler - Responsável por alterar o estado
class CriarPedidoHandler {
  async handle(command: CriarPedidoCommand): Promise<void> {
    // 1. Valida regras de negócio do domínio
    const pedido = new Pedido(command.clienteId, command.itens);
    
    // 2. Persiste no modelo de escrita (Write Model - Relacional/Normalizado)
    await this.pedidoRepository.save(pedido);

    // 3. Publica evento para sincronização assíncrona
    await this.eventBus.publish(new PedidoCriadoEvent(pedido));
  }
}

// Query Handler - Responsável por ler dados otimizados
class ObterDetalhesPedidoHandler {
  async handle(query: ObterPedidoQuery): Promise<PedidoDTO> {
    // Consulta diretamente a base de leitura (Read Model desnormalizado)
    return await this.readDatabase.findPedidoById(query.pedidoId);
  }
}

Considerações finais

O CQRS é uma ferramenta arquitetural indispensável quando atingimos os limites do banco de dados relacional tradicional sob alta carga. Ele resolve o gargalo de I/O ao permitir que a leitura e a escrita cresçam de forma independente, mas exige maturidade da equipe para lidar com consistência eventual e sistemas distribuídos.

Feito!