PostgreSQL: Más Allá del SQL Básico
PostgreSQL no es solo un banco SQL — es una navaja suiza. Columnas JSON, búsqueda full-text, window functions, CTEs e indexación JSONB significan que frecuentemente no necesitas Redis, Elasticsearch o banco de analytics separado.
Tipos de Datos que Vale Conocer
| Tipo | Caso de Uso | Ejemplo |
|---|---|---|
uuid | Primary keys (mejor que serial para sistemas distribuidos) | gen_random_uuid() |
jsonb | Datos semi-estructurados (indexado, queryable) | {"tags": ["dev", "sql"]} |
text | Strings (sin límite, mismo rendimiento que varchar) | Usa text, no varchar |
timestamptz | Timestamps (siempre usa CON timezone) | now() |
JSONB: El Document Store Dentro de Postgres
CREATE TABLE products (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
name text NOT NULL,
metadata jsonb DEFAULT '{}'
);
SELECT name, metadata->>'color' AS color
FROM products
WHERE metadata->>'category' = 'electronics';
CREATE INDEX idx_metadata ON products USING GIN (metadata);CTEs (Common Table Expressions)
WITH active_users AS (
SELECT id, name, email
FROM users
WHERE last_login > now() - interval '30 days'
)
SELECT u.name, COALESCE(o.order_count, 0) as orders
FROM active_users u
LEFT JOIN (
SELECT user_id, COUNT(*) as order_count FROM orders GROUP BY user_id
) o ON u.id = o.user_id;Window Functions
-- Ranking
SELECT name, total_spent,
RANK() OVER (ORDER BY total_spent DESC) as rank
FROM users;
-- Total acumulado
SELECT date, revenue,
SUM(revenue) OVER (ORDER BY date) as running_total
FROM daily_revenue;
-- Comparar con fila anterior
SELECT month, revenue,
LAG(revenue) OVER (ORDER BY month) as prev_month
FROM monthly_revenue;Índices que Importan
-- B-tree (por defecto)
CREATE INDEX idx_users_email ON users (email);
-- Índice parcial
CREATE INDEX idx_active_users ON users (email) WHERE active = true;
-- GIN (para JSONB, arrays, full-text)
CREATE INDEX idx_tags ON posts USING GIN (tags);
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';Tips de Rendimiento
- Siempre usa
EXPLAIN ANALYZE - Usa
timestamptz, nuncatimestampsin timezone - Usa
texten vez devarchar(n) - Agrega índices en foreign keys
- Usa
UPSERT:INSERT ... ON CONFLICT DO UPDATE
Formatea tu SQL: Formateador SQL — pega SQL desordenado, obtén salida formateada.