The function pg_table_size() includes auxiliary relations (TOAST table, free space map, visibility map).
The number in pg_class.relpages should correspond to the result of pg_relation_size(), which only includes the "main" relation (unless instructed otherwise with a 2nd parameter).
SELECT pg_size_pretty(pg_relation_size('tenk1'));
But keep in mind that pg_class.relpages ...
... is only an estimate used by the planner. It is updated by VACUUM, ANALYZE, and a few DDL commands such as CREATE INDEX.
That includes autovacuum. But it's not always up to date after recent write activity.
TOAST table ... free space map, and visibility map ... Is there a way to determine their sizes?
SELECT pg_relation_size(oid, 'fsm') AS free_space_map
, pg_relation_size(oid, 'vm') AS visibility_map
, pg_table_size(reltoastrelid) AS toast_size_incl_vm_fsm
, pg_relation_size(reltoastrelid) AS toast_size_main
FROM pg_class
WHERE oid = 'tenk1'::regclass;
TOAST tables have their own, separate free space map and visibility map. toast_size_incl_vm_fsm shows the total TOAST size including these relation forks, and toast_size_main shows the size of the main TOAST relation.
See:
You can double-check by looking at actual files in the DB directory. See:
Each DB has its own subdirectory by the name of the database OID. It contains files representing all the above relation forks, named after the corresponding OID in pg_class.