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?
| Sintoma | Antes de particionar |
|---|---|
| Consultas lentas | Índices, planos de execução e consultas melhores |
| Leituras demais | Réplicas de leitura e cache |
| Tabela enorme, mas a maior parte antiga | Particionar dentro do servidor por data e arquivar o que é velho |
| CPU e memória no limite | Uma máquina maior |
| Gravações acima do que um servidor aguenta, ou dados que não cabem num servidor | Agora, 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ção | Como funciona | Custos |
|---|---|---|
| Partições no mesmo servidor | PARTITION BY RANGE/HASH/LIST no PostgreSQL | Nenhum servidor a mais; não divide a capacidade da máquina |
| Um banco por cliente ou grupo de clientes | A aplicação escolhe o banco pelo cliente | Simples 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 consultas | Mais um sistema; consultas entre partes têm limites |
| Bancos distribuídos (CockroachDB, YugabyteDB, Spanner, TiDB) | Particionamento e replicação automáticos, com SQL | Latê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 modelo | Modelar pelas consultas, como mostra o tópico de bancos colunares |
| Sharding na aplicação | A aplicação calcula a parte e fala com o banco certo | Toda a complexidade fica no seu código |
Como escolher a chave
Uma boa chave de partição tem quatro propriedades:
| Propriedade | Por quê | Exemplo bom | Exemplo ruim |
|---|---|---|---|
| Está nas consultas frequentes | Elas vão a uma parte só | cliente_id num SaaS, em que tudo é por cliente | id do pedido, se as telas listam por cliente |
| Espalha as gravações | Sem ponto quente | Hash do cliente | Data de criação |
| Agrupa o que é lido junto | Junções e transações dentro de uma parte | Pedidos, itens e pagamentos do mesmo cliente | Pedidos por cliente e itens por produto |
| Tem muitos valores | Permite dividir em muitas partes | Cliente, usuário, dispositivo | Paí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ída | Como |
|---|---|
| Partição exclusiva | O 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óprio | Clientes muito grandes num banco separado, às vezes num plano de assinatura diferente |
O que cruza partes
| Necessidade | Saída |
|---|---|
| Identificadores únicos | Gerados 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ções | Dados que se juntam ficam na mesma parte (mesma chave); tabelas pequenas são replicadas em todas as partes |
| Transações entre partes | Evitar no desenho; quando inevitáveis, sagas, como mostra o tópico de saga e outbox, ou um banco distribuído |
| Relatórios sobre tudo | Um banco analítico alimentado pelas partes, como mostra o tópico de bancos colunares |
| Listagens globais ordenadas | Consultar todas as partes e juntar os resultados; caro, e cada página fica mais cara |
Como crescer
| Forma | Ao acrescentar um servidor |
|---|---|
hash % N | Quase tudo muda de lugar: 80% das chaves no teste |
| Hashing consistente com nós virtuais | Só a parte do novo servidor muda: 19% no teste |
| Muitas partições lógicas, poucos servidores | Começar com, por exemplo, 256 partições lógicas em 4 servidores; crescer é mover partições inteiras para servidores novos |
| Diretório | Mover 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
- 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.
- A chave está nas consultas frequentes, espalha as gravações e agrupa o que é lido junto; nunca a data de criação.
- Clientes gigantes tratados à parte.
- Identificadores gerados fora do banco e unicidade global com tabela própria.
- Junções e transações dentro de uma parte; o resto vai para sagas e para o banco analítico.
- Partições lógicas fixas ou hashing consistente, nunca
hash % Nligado 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.