DevGuideTK
← Trilha Backend

Particionamento

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

O problema: quando um servidor não basta

Réplicas, como mostra o tópico de replicação, dividem as leituras: cada réplica tem uma cópia inteira dos dados. As gravações continuam todas no principal, e o tamanho total dos dados continua tendo de caber em cada máquina. Quando o volume de gravações ou de dados passa do que um servidor aguenta, a saída é dividir os próprios dados.

Particionar é dividir uma tabela em partes pela chave de partição: os pedidos dos clientes de 1 a 50 mil numa parte, os de 50 a 100 mil em outra. Quando as partes ficam em máquinas diferentes, cada uma com a sua fatia, o nome comum é sharding, e cada parte é um shard.

RéplicasPartições em máquinas diferentes
Cada máquina temTodos os dadosUma parte
Divide as leiturasSimSim
Divide as gravaçõesNãoSim
Divide o espaço em discoNãoSim
Consultas que cruzam dadosIguais a um banco sóPrecisam consultar várias partes

Três formas de dividir

FormaComo a chave escolhe a parteBom paraProblema
Por faixacliente_id de 1 a 50.000 na parte 1Consultas por intervalo, dados por dataFaixas desiguais e pontos quentes
Por hashhash(cliente_id) % NDistribuir de forma uniformeFaixas viram consultas em todas as partes
Por lista ou diretórioUma tabela diz em qual parte está cada clienteMover um cliente específico, separar clientes grandesA tabela de diretório vira peça central

A consulta pela chave e a consulta sem ela

O PostgreSQL particiona uma tabela dentro do mesmo servidor, e o comportamento das consultas é o mesmo de um sistema com partes em várias máquinas. Testamos uma tabela de 8 milhões de pedidos dividida em 16 partições por hash de cliente_id, cerca de 500 mil linhas em cada:

ConsultaPartições lidasTempo
WHERE cliente_id = 4242 (a chave)10,4 ms
WHERE id = 123456 (não é a chave, com índice)160,4 ms
WHERE total = 123 AND criado_em < ... (não é a chave, sem índice)16200 ms

No mesmo servidor, ler 16 índices custou quase o mesmo que ler um. Em máquinas diferentes, a conta muda: cada parte consultada é uma ida pela rede, e a consulta só termina quando a parte mais lenta responder. Uma consulta que não informa a chave vira 16 consultas em paralelo, e a carga de cada uma delas pesa em todas as máquinas. As consultas mais frequentes precisam conter a chave de partição.

Unicidade só dentro da partição

O teste mostrou uma restrição que surpreende. A chave primária id, sozinha, foi recusada:

ERROR: unique constraint on partitioned table must include all partitioning columns
DETAIL: PRIMARY KEY constraint on table "pedidos" lacks column "cliente_id"

Cada partição só garante a unicidade dentro de si. A chave primária precisou ser (id, cliente_id), e com ela o banco aceitou dois pedidos com o mesmo id, de clientes diferentes, em partições diferentes. Com as partes em máquinas diferentes, é igual: nenhuma máquina enxerga as outras. Identificadores únicos passam a ser gerados de um jeito que não depende do banco, como UUIDs v7, ou incluem a chave de partição.

O ponto quente

Uma partição só divide a carga se a chave a espalhar. Simulamos três escolhas com 8 partições:

ChaveDistribuição das gravações
Por mês (2026-11), num dia comum100% na partição do mês atual
Hash do cliente, clientes de tamanhos parecidosEntre 12,3% e 12,8% por partição (o ideal é 12,5%)
Hash do cliente, com um cliente dono de 30% dos pedidos38,7% na partição dele, e 8,6% na menor

A partição por data é ótima para apagar dados antigos, como no tópico de séries temporais, e péssima para dividir gravações: todas vão para a partição de hoje. E o hash só espalha o que é diferente: um marketplace com um vendedor gigante, ou um SaaS com um cliente enorme, concentra a carga na partição desse cliente, por melhor que seja o hash. A saída costuma ser tratar o gigante à parte: uma partição só para ele, ou uma chave composta que divide os dados dele.

Acrescentar servidores sem mover tudo

Com hash(chave) % N, a parte de cada chave depende de N. Passar de 4 para 5 servidores muda o resultado da conta para quase todas as chaves, e os dados precisam se mover. O hashing consistente coloca servidores e chaves num mesmo anel de valores de hash: cada chave fica no primeiro servidor depois dela no anel. Um servidor novo só toma as chaves do trecho que ele ocupa.

Medimos com 100 mil chaves, nas cinco linguagens, com o mesmo hash:

Ao passar de 4 para 5 servidoresChaves que mudam de servidor
hash % N79.982 (80%)
Anel de hashing consistente, 100 posições por servidor18.936 (19%)

O ideal é 20%: um quinto das chaves precisa ir para o servidor novo. O anel chegou perto disso; o módulo moveu quatro vezes mais dados que o necessário. As posições múltiplas por servidor (nós virtuais) é que equilibram o anel: com 100 posições cada, os 4 servidores ficaram com entre 24.211 e 26.821 chaves.

Por que isso importa quando a IA escreve o código

Um assistente que "prepara o sistema para escalar" costuma particionar cedo e com a chave errada:

  • Sharding num sistema que caberia folgado num servidor.
  • Chave de partição por data, concentrando todas as gravações na partição atual.
  • Consultas frequentes sem a chave de partição, que viram consultas em todas as partes.
  • Identificadores sequenciais do banco, que se repetem entre partes.
  • hash % N para escolher o servidor, que move quase tudo ao crescer.
  • Transações e junções entre partes tratadas como se fossem num banco só.

O próximo nível compara as formas de particionar e como escolher a chave.

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.

  • Particionamento em cinco minutos

    Explique em no máximo cinco minutos de leitura o que é particionar dados entre máquinas (sharding), para alguém que só usou um banco num servidor.
    
    Cubra só o essencial: a diferença para réplicas, as formas de dividir (faixa, hash, diretório), o papel da chave de partição, os pontos quentes e o que fica difícil (consultas e unicidade entre partes).
    
    Use o exemplo de um SaaS com muitas empresas clientes. No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
  • Escolher a chave de partição

    Quero aprender a escolher a chave de partição de uma tabela.
    
    Aja como um mentor e vá por etapas, esperando a minha resposta em cada uma:
    1. As quatro propriedades de uma boa chave: estar nas consultas, espalhar as gravações, agrupar o que é lido junto e ter muitos valores.
    2. Por que a data de criação é uma chave ruim para dividir gravações.
    3. O efeito de um cliente gigante numa chave por cliente.
    4. Chaves compostas e o custo delas nas consultas.
    5. O que acontece com as consultas que não informam a chave.
    
    Em cada etapa, me descreva um sistema e peça que eu proponha a chave, corrigindo a minha resposta.
  • Hashing consistente

    Quero entender o hashing consistente.
    
    Explique:
    1. Por que hash % N move quase todas as chaves quando N muda, com um exemplo numérico.
    2. O anel: como servidores e chaves são colocados nele.
    3. Por que os nós virtuais equilibram a distribuição.
    4. A alternativa de muitas partições lógicas fixas em poucos servidores.
    5. Por que o hash precisa ser estável e igual em todas as linguagens.
    
    Depois me peça para calcular, num anel pequeno, para onde vão algumas chaves e quais mudam ao entrar um servidor.
  • O que fica difícil com dados particionados

    Quero entender o que fica difícil quando os dados estão divididos entre máquinas.
    
    Explique, com exemplos e as saídas usuais:
    1. Identificadores únicos e unicidade de valores como e-mail.
    2. Junções entre dados de partes diferentes.
    3. Transações que alteram várias partes.
    4. Listagens globais ordenadas e paginadas.
    5. Relatórios sobre todos os dados.
    
    Depois me descreva três funcionalidades e pergunte como eu as implementaria num sistema particionado.