It gets a lot faster if you run the function in a subquery and only decompose the resulting row type in the outer SELECT list:
SELECT s.schemaname, s.relname, st.*
FROM pg_statio_user_tables s
CROSS JOIN LATERAL pgstattuple(s.relid) AS st
ORDER BY 1, 2; -- optional
This way, the function is only called once per row in pg_statio_user_tables. You were stumbling over a weak spot in the Postgres query planner. See:
- How to avoid multiple function evals with the (func()).* syntax in a query?
Since Postgres 9.4 pgstattuple() can take an OID, which is preferable.
PostgreSQL
postgresql.org › docs › current › pgstattuple.html
PostgreSQL: Documentation: 18: F.33. pgstattuple — obtain tuple-level statistics
May 14, 2026 - F.33. pgstattuple — obtain tuple-level statistics # F.33.1. Functions F.33.2. Authors The pgstattuple module provides various functions to obtain tuple-level statistics. …
AWS
aws.amazon.com › blogs › database › improve-postgresql-performance-using-the-pgstattuple-extension
Improve PostgreSQL performance using the pgstattuple extension | Amazon Web Services
April 2, 2025 - In this post, we explore the pgstattuple extension in depth; what insights it offers, how to use it to diagnose issues in Amazon Aurora PostgreSQL-Compatible Edition and Amazon Relational Database Service (Amazon RDS) for PostgreSQL, and best practices for harnessing its capabilities.
GitHub
github.com › postgres › postgres › blob › master › contrib › pgstattuple › pgstattuple.c
postgres/contrib/pgstattuple/pgstattuple.c at master · postgres/postgres
typedef struct pgstattuple_type · { uint64 table_len; uint64 tuple_count; uint64 tuple_len; uint64 dead_tuple_count; uint64 dead_tuple_len; uint64 free_space; /* free/reusable space in bytes */ } pgstattuple_type; · typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber, BufferAccessStrategy); ·
Author postgres
CSE CGI Server
cgi.cse.unsw.edu.au › ~cs9315 › 16s1 › postgresql › documentation › pgstattuple.html
pgstattuple
pgstattuple returns a relation's physical length, percentage of "dead" tuples, and other info. This may help users to determine whether vacuum is necessary or not. The argument is the target relation's name (optionally schema-qualified) or OID.
PIGSTY
pigsty.io › ext › e › pgstattuple
pgstattuple | PIGSTY
March 12, 2026 - pgstattuple provides functions to obtain tuple-level statistics for tables and indexes, including dead tuple counts and free space metrics.
PostgreSQL
postgresql.org › docs › 8.4 › pgstattuple.html
PostgreSQL: Documentation: 8.4: pgstattuple
July 24, 2014 - pgstattuple returns a relation's physical length, percentage of "dead" tuples, and other info. This may help users to determine whether vacuum is necessary or not. The argument is the target relation's name (optionally schema-qualified).
Enteros, Inc
enteros.com › главная страница › enteros’ blog – thoughts on database technology, machine / deep learning, and a generative ai › table bloat estimation in postgresql
TABLE BLOAT ESTIMATION IN POSTGRESQL
December 29, 2022 - Both methods of estimating are very cheap and involve making some educated guesses based on statistics. The “pgstattuple” extension also has a pgstattuple() method, which we will include in our comparisons to get accurate information on bloat, but this method may be expensive because it does a full table scan.
Postgresql
doxygen.postgresql.org › pgstatindex_8c.html
PostgreSQL Source Code: contrib/pgstattuple/pgstatindex.c File Reference
422 errmsg("must be superuser to use pgstattuple functions"))); 423 · 424 relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); 425 rel = relation_openrv(relrv, AccessShareLock); 426 · 427 PG_RETURN_INT64(pg_relpages_impl(rel)); 428} errcode ·