How do I speed up counting rows in a PostgreSQL table?
You can get an estimate from the system table "pg_stat_user_tables".
select schemaname, relname, n_live_tup
from pg_stat_user_tables
where schemaname = 'your_schema_name'
and relname = 'your_table_name';
Count is slow for big tables, so you can get a close estimate this way:
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE relname='tableName';
and its extremely fast, results are not float, but still a close estimate.
reltuples
is a column frompg_class
table, it holds data about "number of rows in the table. This is only an estimate used by the planner. It is updated by VACUUM, ANALYZE, and a few DDL commands such as CREATE INDEX" (manual)- The catalog
pg_class
catalogs tables and most everything else that has columns or is otherwise similar to a table. This includes indexes (but see also pg_index), sequences, views, composite types, and some kinds of special relation (manual) - "Why is "SELECT count(*) FROM bigtable;" slow?" : http://wiki.postgresql.org/wiki/FAQ#Why_is_.22SELECT_count.28.2A.29_FROM_bigtable.3B.22_slow.3F
Aside from running COUNT() on an indexed field (which hopefully 'id' is) - the next best thing would be to actually cache the row count in some table using a trigger on INSERT. Naturally, you'll be checking the cache instead.
For an approximation you can try this (from https://wiki.postgresql.org/wiki/Count_estimate):
select reltuples from pg_class where relname='tablename';
For a very quick estimate:
SELECT reltuples FROM pg_class WHERE relname = 'my_table';
There are several caveats, though. For one, relname
is not necessarily unique in pg_class
. There can be multiple tables with the same relname
in multiple schemas of the database. To be unambiguous:
SELECT reltuples::bigint FROM pg_class WHERE oid = 'my_schema.my_table'::regclass;
If you do not schema-qualify the table name, a cast to regclass
observes the current search_path
to pick the best match. And if the table does not exist (or cannot be seen) in any of the schemas in the search_path
you get an error message. See Object Identifier Types in the manual.
The cast to bigint
formats the real
number nicely, especially for big counts.
Also, reltuples
can be more or less out of date. There are ways to make up for this to some extent. See this later answer with new and improved options:
- Fast way to discover the row count of a table in PostgreSQL
And a query on pg_stat_user_tables
is many times slower (though still much faster than full count), as that's a view on a couple of tables.