To get Schema size :
SELECT schemaname, pg_size_pretty(t.taille::bigint) AS taille_table, pg_size_pretty(t.taille_totale::bigint) AS taille_totale_table
FROM (SELECT schemaname,
sum(pg_relation_size(schemaname || '.' || tablename)) AS taille,
sum(pg_total_relation_size(schemaname || '.' || tablename)) AS taille_totale
FROM pg_tables
WHERE relname_exists(tablename,schemaname) -- see note
GROUP BY schemaname) as t ORDER BY taille_totale DESC;
And for Tables by Schema, you can do this :
SELECT schemaname, tablename, tablespace, pg_size_pretty(taille) AS taille_table, pg_size_pretty(taille_totale) AS taille_totale_table
FROM (SELECT *,
pg_relation_size(schemaname || '.' || tablename) AS taille,
pg_total_relation_size(schemaname || '.' || tablename) AS taille_totale
FROM pg_tables) AS tables
WHERE relname_exists(tablename,schemaname) -- see note
ORDER BY taille_totale DESC;
NOTE: to avoid "ERROR: relation 'x.y' does not exist", needs to guard the string before use it, so
use to_regclass(rel_name)
in Postgres 9.4+... See https://stackoverflow.com/a/24089729
or use a generic (see "SwissKnife libraries") function for any pg version, as below
CREATE or replace FUNCTION relname_exists(text,text default NULL) RETURNS boolean AS $$
SELECT EXISTS (
SELECT 1
FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace,
regexp_split_to_array($1,'\.') t(x) -- not work with quoted names
WHERE CASE
WHEN COALESCE(x[2],'')>'' THEN n.nspname = x[1] AND c.relname = x[2]
WHEN $2 IS NULL THEN n.nspname = 'public' AND c.relname = $1
ELSE n.nspname = $2 AND c.relname = $1
END
)
$$ language SQL IMMUTABLE;