De tablas monstruo a queries voladoras: partitioning real

Trabajaba con tablas de chatbots de 500M+ rows donde DELETE tomaba horas. Database Partitioning te salva: divide monstruos en pedacitos, queries 12x más rápidas, detach histórico en segundos. Código Postgres real que sí funciona.

2 min de lectura
De tablas monstruo a queries voladoras: partitioning real
Photo of Prathamesh Sonpatki

Recuerdo como si fuera ayer: trabajaba en esa empresa de chatbots donde cada día generaban millones de registros. Llevaban años en el mercado, así que las tablas de conversaciones eran monstruos con historial de años. Hacer un simple UPDATE o DELETE era una novela: LIMIT 10k, iterando hasta el cansancio mientras el café se enfriaba.

El post de Last9 sobre Database Partitioning me pegó directo al hígado. "¡Esto nos habría salvado la vida!" pensé. No es teoría bonita; es el antídoto para tablas que se convierten en elefantes. Vamos a desglosarlo como si estuviéramos en el lunch, con código que sí funciona.

Partitioning: dividir para conquistar (sin mover servidores)

En cristiano: Tomas tu tabla gigante y la rompes en pedacitos manejables dentro del mismo servidor. Postgres/MySQL hace la magia: tus queries solo tocan la partición correcta. Tu app no se entera de nada.

No es sharding (eso ya es otro nivel de dolor). Partitioning = mismo servidor, mejor perf, menos drama.

Mi dolor pasado: conversations con 500M+ rows. Un DELETE WHERE created_at < '2024-01-01' tomaba horas y lockeaba todo. Con partitioning: desenchufas la partición vieja en segundos.

Range Partitioning: tu nuevo mejor amigo

Para chatbots, logs, orders —todo lo que tiene timestamps.

-- Tabla madre particionada
CREATE TABLE conversations (
    id BIGSERIAL,
    user_id INT,
    message TEXT,
    created_at TIMESTAMPTZ NOT NULL
) PARTITION BY RANGE (created_at);

-- Particiones mensuales (cron las crea)
CREATE TABLE conv_202501 PARTITION OF conversations
    FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');

Magia pura:

-- Esto SOLO toca conv_202501
SELECT * FROM conversations 
WHERE created_at BETWEEN '2025-01-15' AND '2025-01-20';

Eliminar histórico (el sueño):

ALTER TABLE conversations DETACH PARTITION conv_202401;
DROP TABLE conv_202401;  -- ¡Segundos!

¿Ves la diferencia? Antes: horas de DELETE LIMIT 10k. Ahora: detach y ¡Ka-chow!.

Mi odisea real: del caos al "por qué no lo hicimos antes"

Nuestras queries típicas eran un chiste de terror:

-- ANTES: Full scan 500M rows (minutos)
UPDATE conversations SET status = 'archived' 
WHERE created_at < NOW() - INTERVAL '1 year' LIMIT 10000;
-- x50k iteraciones = pesadilla

Con partitioning:

-- Segundos, cero locks
ALTER TABLE conversations DETACH PARTITION conv_202401;

Ganancias reales:

  • VACUUM por partición = 10x más rápido
  • Queries por fecha tocan solo 1/12 del dataset
  • Mantenimiento sin downtime
  • EXPLAIN deja de dar pesadillas

Otros sabores (elige tu veneno)

List Partitioning (por tenants/regiones):

CREATE TABLE events (
    id BIGSERIAL, region TEXT NOT NULL, payload JSONB
) PARTITION BY LIST (region);

CREATE TABLE events_mx PARTITION OF events 
    FOR VALUES IN ('mx-nte', 'mx-cdmx');

Hash Partitioning (user_id pareja):

CREATE TABLE sessions (
    id BIGSERIAL, user_id INT NOT NULL, data JSONB
) PARTITION BY HASH (user_id);

¿Cuándo meterle mano? (no te emociones)

SÍ, YA:

  • Tablas >50M rows con filtros fecha/region
  • DELETE histórico >5min
  • VACUUM FULL te paraliza
  • Sequential scans en EXPLAIN

NO, PARA:

  • Tablas chicas (<5M)
  • Queries sin partition key (peor que nada)
  • Write-heavy (sharding territory)

Regla de oro: 80%+ de queries deben usar tu partition key.

Mi sentencia final

Last9 lo clava: partitioning antes que sharding. DDL simple, app intacta, resuelve 80% de dramas de tablas gordas.

En mi empresa habríamos ahorrado meses de sufrimiento y miles (en dinero) en infra.

Tu misión 2026: Audit queries → partition key → migra. Tu DBA futuro te mandará birria.

Nos vemos en el próximo EXPLAIN que no te quite el sueño. ¿Qué tabla monstruosa tienes gritando por partitioning?