From b485e75bb2b36e615b09fcede860bc439fc57b4b Mon Sep 17 00:00:00 2001 From: "andres.suarez" Date: Thu, 26 Mar 2026 17:49:12 +0100 Subject: [PATCH 1/2] feat: add pg_class-based table size metrics to postgres_exporter Deploy a custom queries.yml that exposes per-table row estimates and sizes (table, index, toast) via pg_class.reltuples and pg_relation_size(), as a cheap alternative to the disabled stat_user_tables collectors. --- ansible/files/queries.yml | 34 ++++++++++++++++++++ ansible/tasks/internal/postgres-exporter.yml | 9 ++++++ 2 files changed, 43 insertions(+) create mode 100644 ansible/files/queries.yml diff --git a/ansible/files/queries.yml b/ansible/files/queries.yml new file mode 100644 index 0000000000..9e1bb88478 --- /dev/null +++ b/ansible/files/queries.yml @@ -0,0 +1,34 @@ +pg_table_size: + query: | + SELECT + n.nspname AS schema, + c.relname AS table, + c.reltuples AS row_estimate, + pg_total_relation_size(c.oid) AS total_bytes, + pg_relation_size(c.oid) AS table_bytes, + pg_indexes_size(c.oid) AS index_bytes, + pg_total_relation_size(c.reltoastrelid) AS toast_bytes + 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') + metrics: + - schema: + usage: LABEL + - table: + usage: LABEL + - row_estimate: + usage: GAUGE + description: "Estimated row count from pg_class.reltuples" + - total_bytes: + usage: GAUGE + description: "Total size including indexes and toast" + - table_bytes: + usage: GAUGE + description: "Table data size" + - index_bytes: + usage: GAUGE + description: "Total index size" + - toast_bytes: + usage: GAUGE + description: "Toast size" diff --git a/ansible/tasks/internal/postgres-exporter.yml b/ansible/tasks/internal/postgres-exporter.yml index 0292157b2d..f4ec54d951 100644 --- a/ansible/tasks/internal/postgres-exporter.yml +++ b/ansible/tasks/internal/postgres-exporter.yml @@ -35,6 +35,15 @@ extra_opts: [--strip-components=1] become: yes +- name: deploy queries.yml for custom metrics + copy: + src: files/queries.yml + dest: /opt/postgres_exporter/queries.yml + owner: root + group: root + mode: '0644' + become: yes + - name: exporter create a service template: src: files/postgres_exporter.service.j2 From 876c8c4f118fb37e5e060951f97435e85edf2290 Mon Sep 17 00:00:00 2001 From: "andres.suarez" Date: Fri, 27 Mar 2026 09:05:53 +0100 Subject: [PATCH 2/2] feat: add pg_class-based table size metrics to postgres_exporter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deploys a custom `queries.yml` for postgres_exporter that exposes per-table row estimates and sizes via `pg_class`, as a cheap alternative to the disabled `stat_user_tables` collectors. `--no-collector.stat_user_tables` and `--no-collector.statio_user_tables` are disabled because `pg_stat_user_tables` row counts are expensive on large DBs. `pg_class.reltuples` gives a good-enough estimate maintained by autovacuum — no sequential scan, negligible cost. - `ansible/files/queries.yml` — new custom query exposing `pg_table_size` metric family: `row_estimate`, `total_bytes`, `table_bytes`, `index_bytes`, `toast_bytes` (per schema/table) - `ansible/tasks/internal/postgres-exporter.yml` — Ansible task to deploy `queries.yml` to `/opt/postgres_exporter/queries.yml` The service already had `--extend.query-path="/opt/postgres_exporter/queries.yml"` in its ExecStart, so no service template change was needed. Manually deployed to a staging DB and verified via the metrics endpoint. All 5 metric families scraped correctly across `auth`, `storage`, and `vault` schemas. Fixed a `NaN` edge case for `toast_bytes` on tables without a toast table using `COALESCE(pg_total_relation_size(NULLIF(c.reltoastrelid, 0)), 0)`. Note: `row_estimate = -1` is expected on empty/fresh tables — it means autovacuum hasn't run yet. Will show real estimates on populated DBs. --- ansible/files/queries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/files/queries.yml b/ansible/files/queries.yml index 9e1bb88478..a906819b50 100644 --- a/ansible/files/queries.yml +++ b/ansible/files/queries.yml @@ -7,7 +7,7 @@ pg_table_size: pg_total_relation_size(c.oid) AS total_bytes, pg_relation_size(c.oid) AS table_bytes, pg_indexes_size(c.oid) AS index_bytes, - pg_total_relation_size(c.reltoastrelid) AS toast_bytes + COALESCE(pg_total_relation_size(NULLIF(c.reltoastrelid, 0)), 0) AS toast_bytes FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = 'r'