O Modelo de Particionamento
O particionamento divide uma tabela lógica em várias peças físicas, permitindo que o código da aplicação continue consultando-a como se fosse uma única tabela.
Busque em todas as páginas da documentação
O particionamento divide uma tabela lógica em várias peças físicas, permitindo que o código da aplicação continue consultando-a como se fosse uma única tabela.
Essa divisão parece um detalhe de armazenamento, mas a chave de partição que você escolhe se torna uma promessa estrutural sobre como cada consulta futura, índice e trabalho de manutenção se comportará.
Esta página constrói o modelo mental por trás do particionamento declarativo do PostgreSQL, para que as páginas mais mecânicas desta seção (sintaxe DDL, poda, retenção) façam sentido como consequências desse modelo, em vez de receitas isoladas.
Uma tabela particionada no PostgreSQL é declarada uma vez, com PARTITION BY RANGE, LIST ou HASH em uma coluna de chave de partição escolhida.
Cada partição filha é uma tabela física real que contém uma fatia definida de linhas, e a própria tabela pai não armazena nenhuma linha.
CREATE TABLE events (
event_id bigint GENERATED ALWAYS AS IDENTITY,
occurred_at timestamptz NOT NULL,
PRIMARY KEY (event_id, occurred_at)
) PARTITION BY RANGE (occurred_at);Particionamento por intervalo (Range partitioning) atribui linhas a uma partição com base em onde um valor se encaixa entre limites, e é o ajuste natural para dados de séries temporais como eventos ou logs.
Particionamento por lista (List partitioning) atribui linhas por associação a valores exatos, o que se encaixa em colunas de baixa cardinalidade como região ou nível de tenant.
Particionamento por hash (Hash partitioning) distribui linhas uniformemente por um número fixo de partições usando um hash da chave, para casos onde não existe um agrupamento natural por intervalo ou lista, mas a distribuição uniforme ainda é importante.
A escolha entre esses três é realmente uma escolha sobre em que as futuras consultas filtrarão, porque é isso que determina se o PostgreSQL pode pular partições inteiramente.
A capacidade do planejador de pular partições irrelevantes é chamada de poda de partições (partition pruning), e é todo o argumento de desempenho para o particionamento.
Quando a cláusula WHERE de uma consulta restringe a chave de partição a um intervalo ou a um conjunto de valores, o planejador pode determinar no momento do planejamento (ou em alguns casos no momento da execução) quais partições filhas podem possivelmente conter linhas correspondentes, e escanear apenas essas.
EXPLAIN (COSTS OFF)
SELECT * FROM events WHERE occurred_at >= '2026-01-01' AND occurred_at < '2026-02-01';
-- Um plano podado toca apenas a partição events_2026_01Se uma consulta não filtra na chave de partição, a poda não pode ocorrer, e a consulta escaneia todas as partições, o que pode ser mais lento do que a consulta equivalente em uma tabela não particionada devido ao sobrecarga adicional de planejamento.
É por isso que a chave de partição não é um detalhe de implementação de armazenamento para escolher por último; é uma previsão sobre a forma dominante da cláusula WHERE no fluxo de trabalho de consulta real da tabela.
Índices em uma tabela particionada são declarados uma vez na tabela pai e o PostgreSQL propaga a definição para todas as partições filhas existentes e futuras, mas cada filha ainda armazena e mantém seu próprio índice físico.
Isso significa que adicionar um índice a uma tabela particionada com muitas partições é, na verdade, adicionar muitos índices de uma vez, e deve ser planejado com o mesmo cuidado que qualquer outro DDL de tabela grande.
Uma partição padrão (default partition) existe para capturar linhas que não correspondem a nenhum limite de partição explícito, o que evita falhas de inserção durante a implantação, mas tem um custo: linhas na partição padrão não podem ser podadas de nenhuma consulta, pois o planejador não pode descartá-la para nenhum predicado.
O caso de manutenção do particionamento é frequentemente o argumento mais forte na prática, mesmo antes da velocidade da consulta.
Excluir um mês de dados históricos de uma tabela de um bilhão de linhas não particionada significa um DELETE lento e com muito log de transações, que precisa ser vacuumed depois; desanexar uma partição é uma operação rápida de metadados que remove os dados instantaneamente.
ALTER TABLE events DETACH PARTITION events_2025_01;Vacuum e autovacuum também se beneficiam do particionamento indiretamente, pois cada partição é uma tabela separada para fins de autovacuum, então uma partição recente e ativa, que é atualizada frequentemente, pode ser vacuumed sem tocar em partições históricas frias que não mudaram.
A escolha entre particionamento por intervalo, lista e hash em escala real geralmente se resume a qual deles corresponde à forma real de filtro em produção, não qual deles é teoricamente mais elegante para os dados.
| Abordagem | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
| Particionamento por intervalo | Ajuste natural para dados de séries temporais; suporta retenção fácil via detach | Requer criação contínua de partições à medida que o tempo avança | Tabelas de eventos, logs e séries temporais |
| Particionamento por lista | Mapeamento direto para um conjunto conhecido e pequeno de valores | Novos valores precisam de novas partições ou um padrão "catch-all" | Região, nível de tenant ou outras colunas de baixa cardinalidade |
| Particionamento por hash | Distribuição de escrita uniforme sem chave de intervalo ou lista natural | Nenhum benefício de poda, a menos que as consultas filtrem na chave de hash com igualdade | Tabelas de alta escrita que precisam de distribuição, não acesso baseado em tempo ou categoria |
| Sem particionamento | Mais simples de operar; nenhuma necessidade de planejamento de poda | Custo de exclusão em massa e vacuum escala com o tamanho total da tabela | Tabelas que permanecem pequenas ou cujas exclusões são raras |
O particionamento também interage com as regras de chave primária e constraints únicas no PostgreSQL: qualquer constraint única, incluindo a chave primária, deve incluir a chave de partição como parte de suas colunas, pois a unicidade só pode ser aplicada dentro de cada partição física, não em todas elas de uma vez.
Essa constraint molda o design da chave mais cedo do que a maioria das equipes espera, e vale a pena resolvê-la durante o estágio de modelagem lógica em vez de descobri-la ao escrever a primeira instrução CREATE TABLE PARTITION BY.
WHERE tende a produzir uma tabela que não consegue podar as consultas que realmente rodam contra ela.ALTER leve.É uma tabela lógica declarada com PARTITION BY, apoiada por múltiplas tabelas filhas físicas que cada uma contém uma fatia definida de linhas.
A própria tabela pai não armazena nenhuma linha.
A poda de partições é a capacidade do planejador de pular tabelas filhas que não podem possivelmente conter linhas correspondentes, com base na cláusula WHERE da consulta.
É o principal benefício de desempenho do particionamento, e só é ativado quando uma consulta filtra na chave de partição.
O planejador não pode descartar nenhuma partição, então ele escaneia todas elas, o que pode ser mais lento do que consultar uma tabela não particionada equivalente devido ao sobrecarga adicional de planejamento por partição.
Constraints de unicidade, incluindo a chave primária, só podem ser aplicadas dentro de uma única partição física, não em todas as partições de uma vez.
Incluir a chave de partição na constraint é como o PostgreSQL garante que a unicidade global seja realmente mantida.
Sim, quando dados antigos se alinham com partições inteiras - desanexar ou descartar uma partição é uma operação rápida de metadados, em comparação com um DELETE linha por linha que depois precisa ser vacuumed em uma tabela não particionada.
Não - um índice declarado na tabela pai se propaga para todas as partições filhas existentes e futuras automaticamente.
Cada filha ainda armazena sua própria cópia física desse índice.
Uma partição padrão captura linhas que não correspondem aos limites de nenhuma partição explícita, evitando falhas de inserção durante a implantação ou valores inesperados.
Ela deve ser monitorada e mantida pequena, pois as linhas dentro dela nunca podem ser podadas.
Indiretamente, sim - cada partição é uma tabela separada para fins de autovacuum, então uma partição recente e ativa pode ser vacuumed frequentemente enquanto partições históricas frias são deixadas intocadas.
Não como uma operação leve - a chave de partição afeta todas as constraints únicas na tabela, então mudá-la geralmente requer a reconstrução da tabela sob um novo esquema de particionamento.
É por isso que a chave merece uma análise real antes que a primeira partição seja criada.
Ambos, mas o caso de manutenção (retenção rápida via detach, vacuum isolado por partição) é frequentemente a vitória mais forte e confiável em produção, antes da velocidade bruta da consulta.
A velocidade da consulta depende inteiramente se a poda realmente se aplica.
Não há um número universal, mas o sobrecarga de planejamento cresce com a contagem de partições, e uma contagem de partições ilimitada e em constante crescimento (uma por dia para sempre, sem retenção) eventualmente sobrecarrega o tempo de planejamento, mesmo quando a poda funciona corretamente.
Políticas de retenção existem em parte para manter isso limitado.
Versões da Stack: Esta página foi escrita para PostgreSQL 18.4 (estável 18, manutenção 17).
Revisado por Chris St. John·Última atualização: 15 de jul. de 2026