Particionamiento declarativo en PostgreSQL | Nicolás Garzón
Particionar no hace una tabla mágicamente rápida. Divide sus filas en relaciones físicas para que pruning, mantenimiento y lifecycle trabajen por subconjuntos previsibles.
Una tabla particionada dirige cada fila a una partition según una key:
Texto
Copiar tabla lógica orders
→ RANGE por created_at
→ orders_2026_01, orders_2026_02, ...La consulta sigue apuntando a orders; el planner decide qué partitions necesita.
Fechas o rangos ordenados:
SQL
Copiar CREATE TABLE events ( . . . ) PARTITION BY RANGE ( occurred_at) ; Valores discretos como región o tenant group.
Distribuye valores cuando no existe rango natural.
SQL
Copiar CREATE TABLE orders (
id bigint NOT NULL ,
created_at timestamptz NOT NULL ,
business_id bigint NOT NULL ,
total numeric ( 14 , 2 ) NOT NULL ,
PRIMARY KEY ( created_at, id)
) PARTITION BY RANGE ( created_at) ;
CREATE TABLE orders_2026_07 PARTITION OF orders
FOR VALUES FROM ( '2026-07-01' ) TO ( '2026-08-01' ) ; Los límites usan [from, to). La próxima partition comienza exactamente en el límite anterior.
SQL
Copiar WHERE created_at >= $1 AND created_at < $2 permite excluir partitions cuando el predicado se relaciona claramente con la key. Envolverla en funciones o usar condiciones poco demostrables puede impedir pruning.
Verifica con EXPLAIN; no asumas que ocurre.
Cada partition tiene índices físicos propios. Crear un índice sobre la tabla padre crea/adjunta índices en partitions según versión y operación.
Una UNIQUE o PRIMARY KEY global normalmente debe incluir todas las columnas de partition key, porque PostgreSQL no posee un índice único global entre partitions.
Esto afecta diseños como PRIMARY KEY(id) cuando particionas por fecha.
Captura filas fuera de rangos:
SQL
Copiar CREATE TABLE orders_default PARTITION OF orders DEFAULT ; Evita fallos inesperados, pero puede ocultar que faltó crear una partition. Monitorea su crecimiento.
Añadir una partition nueva puede requerir validar que la default no contiene filas de ese rango; constraints previas reducen el scan/bloqueo.
SQL
Copiar ALTER TABLE orders DETACH PARTITION orders_2024_01;
DROP TABLE orders_2024_01; Retirar una partition puede ser mucho más barato que borrar millones de filas y vacuum posterior.
También permite archivar, comprimir externamente o mover tablespaces según estrategia.
Vacuum y analyze operan por partition.
Índices se reconstruyen por partition.
Backups y restores siguen considerando el conjunto.
Muchas partitions aumentan catálogo, planificación y operación.
No crees una partition por customer si existen cientos de miles.
Una partition puede particionarse de nuevo, por ejemplo mes y luego hash. Aumenta complejidad; solo se justifica con volumen y mantenimiento claros.
Si no existe partition compatible, el INSERT falla. Automatiza creación antes del periodo, no después del incidente.
Actualizar la partition key puede mover la fila entre partitions y tener implicaciones de locks, triggers y concurrencia.
Texto
Copiar partitioning
→ una instancia/cluster lógico
→ planner consulta partitions
sharding
→ datos repartidos entre servidores
→ coordinación distribuidaParticionar no elimina límites de CPU, memoria o disponibilidad de una sola instancia.
Tablas muy grandes con filtros frecuentes por key.
Retención por periodos.
Cargas y mantenimiento por bloques.
Pruning significativo.
Operaciones administrativas aislables.
Tabla pequeña.
Queries no filtran por partition key.
Unicidad global incompatible.
Demasiadas partitions.
Se usa para evitar índices o modelado.
Parámetros preparados pueden afectar pruning según plan.
Foreign keys hacia/desde particionadas dependen de versión y diseño.
RLS y triggers deben verificarse en parent/partitions.
Attach de tabla existente exige constraints compatibles.
Clock/timezone incorrectos crean filas en periodo equivocado.
Particionar por una columna que las queries no usan.
Crear miles de partitions diminutas.
Olvidar estrategia de creación futura.
Esperar unicidad global sin incluir key.
Confundir pruning con index scan.
No monitorear default partition.
EXPLAIN con un periodo.
Query sin filtro de key.
Insert fuera de rango.
Cambio de periodo.
Attach/detach.
Índices y constraints.
Prepared statements.
Retención y backup.
Planning time con muchas partitions.
La key debe alinearse con acceso y lifecycle.
Pruning excluye relations; un índice encuentra filas dentro de ellas.
Unicidad global tiene restricciones.
El beneficio operativo puede ser mayor que el de consulta.
Demasiadas partitions son deuda.
¿Por qué una PK puede necesitar incluir created_at?
¿Qué diferencia hay entre pruning e índice?
¿Qué riesgo tiene una default partition?
¿Por qué partitioning no es sharding?
Ver respuestas
Porque no existe un índice único global entre partitions y la key identifica la partition.
Pruning descarta partitions; el índice busca dentro de las restantes.
Puede acumular silenciosamente filas cuyo rango no fue creado.
Todas las partitions siguen dentro del mismo sistema PostgreSQL.
Paginación con OFFSET y keyset convierte el orden de una consulta en un contrato estable.