DevGuideTK
← Trilha Backend

Particionamento

Como dividir os dados entre máquinas e o custo de escolher mal a chave de partição.

As decisões de particionamento são cinco: se é hora de particionar, onde, por qual chave, como lidar com o que cruza partes e como crescer.

É hora de particionar?

SintomaAntes de particionar
Consultas lentasÍndices, planos de execução e consultas melhores
Leituras demaisRéplicas de leitura e cache
Tabela enorme, mas a maior parte antigaParticionar dentro do servidor por data e arquivar o que é velho
CPU e memória no limiteUma máquina maior
Gravações acima do que um servidor aguenta, ou dados que não cabem num servidorAgora, sim: particionar entre máquinas

Particionar dentro do mesmo servidor (o particionamento declarativo do PostgreSQL) é barato e resolve retenção e manutenção de tabelas grandes. Particionar entre máquinas é caro e só se justifica pela última linha.

Onde particionar

OpçãoComo funcionaCustos
Partições no mesmo servidorPARTITION BY RANGE/HASH/LIST no PostgreSQLNenhum servidor a mais; não divide a capacidade da máquina
Um banco por cliente ou grupo de clientesA aplicação escolhe o banco pelo clienteSimples de raciocinar; migrações em muitos bancos
Extensão de sharding (Citus para PostgreSQL, Vitess para MySQL)O banco distribui as tabelas e roteia as consultasMais um sistema; consultas entre partes têm limites
Bancos distribuídos (CockroachDB, YugabyteDB, Spanner, TiDB)Particionamento e replicação automáticos, com SQLLatência maior por gravação; custo; diferenças de comportamento
Bancos NoSQL com partição nativa (Cassandra, DynamoDB, MongoDB)A chave de partição faz parte do modeloModelar pelas consultas, como mostra o tópico de bancos colunares
Sharding na aplicaçãoA aplicação calcula a parte e fala com o banco certoToda a complexidade fica no seu código

Como escolher a chave

Uma boa chave de partição tem quatro propriedades:

PropriedadePor quêExemplo bomExemplo ruim
Está nas consultas frequentesElas vão a uma parte sócliente_id num SaaS, em que tudo é por clienteid do pedido, se as telas listam por cliente
Espalha as gravaçõesSem ponto quenteHash do clienteData de criação
Agrupa o que é lido juntoJunções e transações dentro de uma partePedidos, itens e pagamentos do mesmo clientePedidos por cliente e itens por produto
Tem muitos valoresPermite dividir em muitas partesCliente, usuário, dispositivoPaís, status

Num sistema multiempresa (SaaS), a empresa cliente costuma ser a chave natural: quase toda consulta já filtra por ela, e os dados de uma empresa raramente se misturam com os de outra. O cuidado é com os clientes gigantes: no teste, um cliente com 30% dos pedidos deixou uma partição com 38,7% da carga.

Clientes gigantes

SaídaComo
Partição exclusivaO diretório manda o cliente grande para uma parte só dele
Chave composta(cliente_id, hash(pedido_id) % k) divide o cliente em k partes, ao custo de consultar k partes para ele
Banco próprioClientes muito grandes num banco separado, às vezes num plano de assinatura diferente

O que cruza partes

NecessidadeSaída
Identificadores únicosGerados fora do banco (UUID v7) ou compostos com a chave de partição; no teste, id sozinho se repetiu entre partições
Unicidade de um valor global (e-mail)Uma tabela de unicidade particionada pelo próprio valor, ou um serviço central
JunçõesDados que se juntam ficam na mesma parte (mesma chave); tabelas pequenas são replicadas em todas as partes
Transações entre partesEvitar no desenho; quando inevitáveis, sagas, como mostra o tópico de saga e outbox, ou um banco distribuído
Relatórios sobre tudoUm banco analítico alimentado pelas partes, como mostra o tópico de bancos colunares
Listagens globais ordenadasConsultar todas as partes e juntar os resultados; caro, e cada página fica mais cara

Como crescer

FormaAo acrescentar um servidor
hash % NQuase tudo muda de lugar: 80% das chaves no teste
Hashing consistente com nós virtuaisSó a parte do novo servidor muda: 19% no teste
Muitas partições lógicas, poucos servidoresComeçar com, por exemplo, 256 partições lógicas em 4 servidores; crescer é mover partições inteiras para servidores novos
DiretórioMover clientes um a um, atualizando a tabela de diretório

A terceira forma é a mais usada na prática: o número de partições lógicas nunca muda, e a chave de cada registro nunca muda de partição. Só o mapa "partição lógica para servidor" muda, e as partições se movem inteiras.

Resumo da decisão

  1. Particione entre máquinas só quando um servidor não bastar para as gravações ou os dados; antes, índices, réplicas, cache e partições no mesmo servidor.
  2. A chave está nas consultas frequentes, espalha as gravações e agrupa o que é lido junto; nunca a data de criação.
  3. Clientes gigantes tratados à parte.
  4. Identificadores gerados fora do banco e unicidade global com tabela própria.
  5. Junções e transações dentro de uma parte; o resto vai para sagas e para o banco analítico.
  6. Partições lógicas fixas ou hashing consistente, nunca hash % N ligado ao número de servidores.

O próximo nível mostra o hashing consistente nas cinco linguagens e o particionamento no PostgreSQL.

Prompts para aprofundar

Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.

  • Decidir se é hora de particionar

    Estou pensando em particionar o banco do meu sistema.
    
    Pergunte o volume de dados, a taxa de gravações e leituras, o tamanho das maiores tabelas, o que já foi feito (índices, réplicas, cache, máquina maior) e onde está o gargalo.
    
    Diga com franqueza se é hora de particionar entre máquinas. Se não for, liste o que fazer antes, em ordem. Se for, compare particionamento no mesmo servidor, um banco por cliente, extensões como Citus ou Vitess e bancos distribuídos para o meu caso.
  • Desenhar o particionamento do meu sistema

    Decidi particionar os dados do meu sistema e quero desenhar isso com cuidado.
    
    Pergunte quais são as tabelas principais, as consultas mais frequentes, como os dados se relacionam e se há clientes muito maiores que os outros.
    
    Proponha:
    1. A chave de partição e por quê.
    2. Quais tabelas ficam juntas na mesma parte, e quais são replicadas em todas.
    3. Como gerar identificadores e garantir unicidade global.
    4. Como lidar com os clientes gigantes.
    5. Como crescer, com partições lógicas ou hashing consistente.
  • Migrar para um banco particionado

    Preciso migrar um banco que não é particionado para um particionado, com o sistema no ar.
    
    Pergunte qual banco e ferramenta de particionamento eu uso, o volume e quanto tempo de indisponibilidade é aceitável.
    
    Monte comigo o plano: preparar o esquema e as chaves, copiar os dados em lotes, manter os dois sincronizados durante a transição, trocar as leituras e as gravações, conferir os dados e voltar atrás se algo der errado.