Obtenir la taille des tables, index et bases dans PostgreSQL

La requête que tout le monde cherche vraiment — les tables les plus volumineuses, index compris — puis les trois fonctions de taille et ce que chacune mesure réellement.

-- Les 20 plus grosses tables (index et TOAST inclus) :
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;

Les trois fonctions de taille, sans ambiguïté

FonctionCe qu'elle mesure
pg_relation_size('t')Le heap principal uniquement — sans les index, sans le TOAST (le stockage déporté pour les grandes valeurs).
pg_table_size('t')La table proprement dite : heap + TOAST + cartes auxiliaires. Toujours sans les index.
pg_total_relation_size('t')Tout : table + TOAST + tous ses index. C'est « combien de disque cette table me coûte-t-elle ».

Encapsulez n'importe laquelle dans pg_size_pretty(...) pour des unités lisibles. Une table comportant de longues colonnes text/JSONB peut avoir la majeure partie de ses octets dans le TOAST — si pg_table_size est bien supérieure à pg_relation_size, c'est là qu'ils se trouvent.

Autres requêtes en une ligne

-- Taille d'une seule table / d'un index / d'une base :
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()));

-- Toutes les bases du cluster :
SELECT datname, pg_size_pretty(pg_database_size(datname))
FROM pg_database
ORDER BY pg_database_size(datname) DESC;

-- Les plus gros index :
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;

Taille sur disque ≠ données vivantes

Ces fonctions mesurent le disque alloué, ce qui inclut le bloat : l'espace occupé par les versions de lignes mortes que le vacuum n'a pas récupéré (et qu'un vacuum ordinaire rend à la table, pas au système d'exploitation). Une table de 50 Go peut ne contenir que 20 Go de lignes vivantes. Si une table paraît bien trop grosse pour son nombre de lignes, il s'agit d'une enquête sur le bloat, pas d'une mise à niveau de stockage.

Tables partitionnées : le parent lui-même est vide — additionnez les partitions, par exemple en joignant pg_inherits, ou examinez-les rapidement avec \d+ parent_name dans psql.

🔍 Table étonnamment volumineuse ? Lisez VACUUM, autovacuum et bloat. Disque réellement en train de se remplir ? Il existe une page d'erreur pour No space left on device — vérifiez les slots de réplication avant d'acheter du stockage.