Cómo obtener el tamaño de tablas, índices y bases de datos en PostgreSQL

La consulta que todo el mundo quiere de verdad — las tablas más grandes, índices incluidos — y luego las tres funciones de tamaño y qué mide realmente cada una.

-- Las 20 tablas más grandes (índices y TOAST incluidos):
SELECT c.oid::regclass AS table_name,
       pg_size_pretty(pg_total_relation_size(c.oid)) AS total,
       pg_size_pretty(pg_table_size(c.oid))          AS table_only,
       pg_size_pretty(pg_indexes_size(c.oid))        AS indexes
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
  AND n.nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_total_relation_size(c.oid) DESC
LIMIT 20;

Las tres funciones de tamaño, desambiguadas

FunciónQué mide
pg_relation_size('t')Solo el heap principal — sin índices, sin TOAST (el almacenamiento fuera de línea para valores grandes).
pg_table_size('t')La tabla propiamente dicha: heap + TOAST + mapas auxiliares. Sigue sin incluir índices.
pg_total_relation_size('t')Todo: tabla + TOAST + todos sus índices. Esto es "cuánto disco me cuesta esta tabla".

Envuelve cualquiera de ellas en pg_size_pretty(...) para obtener unidades legibles. Una tabla con columnas de texto/JSONB largas puede tener la mayoría de sus bytes en TOAST — si pg_table_size es mucho mayor que pg_relation_size, ahí es donde están.

Más consultas de una línea

-- Tamaño de una sola tabla / índice / base de datos:
SELECT pg_size_pretty(pg_total_relation_size('public.orders'));
SELECT pg_size_pretty(pg_relation_size('orders_created_at_idx'));
SELECT pg_size_pretty(pg_database_size(current_database()));

-- Todas las bases de datos del clúster:
SELECT datname, pg_size_pretty(pg_database_size(datname))
FROM pg_database
ORDER BY pg_database_size(datname) DESC;

-- Los índices más grandes:
SELECT c.oid::regclass AS index_name,
       pg_size_pretty(pg_relation_size(c.oid)) AS size
FROM pg_class c
WHERE c.relkind = 'i'
ORDER BY pg_relation_size(c.oid) DESC
LIMIT 20;

Tamaño en disco ≠ datos vivos

Estas funciones miden el disco asignado, que incluye el bloat: espacio ocupado por versiones de filas muertas que vacuum no ha reclamado (y que un vacuum normal devuelve a la tabla, no al sistema operativo). Una tabla de 50 GB podría contener 20 GB de filas vivas. Si una tabla parece demasiado grande para su número de filas, eso es una investigación de bloat, no una ampliación de almacenamiento.

Tablas particionadas: el padre en sí está vacío — suma las particiones, por ejemplo uniendo con pg_inherits, o échales un vistazo con \d+ parent_name en psql.

🔍 ¿Una tabla sospechosamente grande? Lee VACUUM, autovacuum y bloat. ¿Se está quedando sin disco de verdad? Hay una página de error para No space left on device — comprueba los slots de replicación antes de comprar almacenamiento.