Skip to main content
View rawEdit

Table metrics

Table-level statistics. In this stack they come from the table_stats metric group, whose query reads pg_stat_all_tables (not pg_stat_user_tables). Series are exported as pgwatch_table_stats_<column>.

Data sources​

Metric groupUnderlying viewDescription
table_statspg_stat_all_tablesTable access, modification, tuple, vacuum, and size stats
pg_classpg_classTable sizes (pgwatch_pg_class_*)
db_size–Database size (pgwatch_db_size_size_b)

Core metrics​

All series are pgwatch_table_stats_<column>. There are no _total suffixes and no pg_statio_user_tables_* / pg_table_size_bytes series.

Access metrics​

MetricTypeDescription
pgwatch_table_stats_seq_scanCounterSequential scans initiated
pgwatch_table_stats_seq_tup_readCounterRows fetched by sequential scans
pgwatch_table_stats_idx_scanCounterIndex scans initiated
pgwatch_table_stats_idx_tup_fetchCounterRows fetched by index scans

Modification metrics​

MetricTypeDescription
pgwatch_table_stats_n_tup_insCounterRows inserted
pgwatch_table_stats_n_tup_updCounterRows updated
pgwatch_table_stats_n_tup_delCounterRows deleted
pgwatch_table_stats_n_tup_hot_updCounterHOT updates (heap-only tuple)

Tuple metrics​

MetricTypeDescription
pgwatch_table_stats_n_live_tupGaugeEstimated live rows
pgwatch_table_stats_n_dead_tupGaugeEstimated dead rows

Vacuum metrics​

MetricTypeDescription
pgwatch_table_stats_seconds_since_last_vacuumGaugeSeconds since last (auto)vacuum
pgwatch_table_stats_seconds_since_last_analyzeGaugeSeconds since last (auto)analyze
pgwatch_table_stats_vacuum_countCounterManual vacuum count
pgwatch_table_stats_autovacuum_countCounterAutovacuum count
pgwatch_table_stats_analyze_countCounterManual analyze count
pgwatch_table_stats_autoanalyze_countCounterAutoanalyze count

Size metrics​

MetricTypeDescription
pgwatch_table_stats_table_size_bGaugeTable size in bytes (excluding indexes)
pgwatch_table_stats_total_relation_size_bGaugeTotal size (table + indexes + toast)
pgwatch_table_stats_toast_size_bGaugeTOAST size in bytes

Freeze-age metrics​

MetricTypeDescription
pgwatch_table_stats_tx_freeze_ageCounterTransaction-id freeze age
pgwatch_table_stats_mxid_freeze_ageCounterMultixact-id freeze age

Labels​

The table_stats metric is grouped by schema and table, so it carries these labels (plus the instance labels). Note the names are schema / table_name / table_full_name (not schemaname / relname), and the cluster label is cluster (not cluster_name).

LabelDescriptionExample
table_nameTable nameusers
table_full_nameSchema-qualified table namepublic.users
schemaSchema namepublic
datnameDatabase namemyapp
clusterCluster identifier (from custom_tags.cluster)production
node_nameNode identifierprimary

Common queries​

Sequential scan ratio​

rate(pgwatch_table_stats_seq_scan[5m])
/
(
rate(pgwatch_table_stats_seq_scan[5m])
+
rate(pgwatch_table_stats_idx_scan[5m])
)

Tables with high dead tuple ratio​

pgwatch_table_stats_n_dead_tup
/
(pgwatch_table_stats_n_live_tup + pgwatch_table_stats_n_dead_tup)
> 0.1

HOT update ratio​

rate(pgwatch_table_stats_n_tup_hot_upd[5m])
/
rate(pgwatch_table_stats_n_tup_upd[5m])

Tables not vacuumed recently​

pgwatch_table_stats_seconds_since_last_vacuum > 86400

Largest tables​

topk(10, pgwatch_table_stats_total_relation_size_b)

Write-heavy tables​

topk(10,
rate(pgwatch_table_stats_n_tup_ins[5m])
+
rate(pgwatch_table_stats_n_tup_upd[5m])
+
rate(pgwatch_table_stats_n_tup_del[5m])
)

Dashboard usage​

These metrics are used in:

Interpreting metrics​

Sequential vs index scans​

High sequential scan rate on large tables suggests missing indexes:

select
schemaname,
relname,
seq_scan,
idx_scan,
pg_size_pretty(pg_relation_size(relid)) as size
from pg_stat_user_tables
where seq_scan > idx_scan
and pg_relation_size(relid) > 10000000
order by seq_scan desc;

Dead tuple accumulation​

Dead tuples indicate rows deleted/updated but not yet vacuumed:

select
relname,
n_live_tup,
n_dead_tup,
round(100.0 * n_dead_tup / nullif(n_live_tup + n_dead_tup, 0), 1) as dead_pct,
last_autovacuum
from pg_stat_user_tables
where n_dead_tup > 1000
order by n_dead_tup desc;

HOT update efficiency​

HOT updates avoid index updates — higher ratio is better:

select
relname,
n_tup_upd,
n_tup_hot_upd,
round(100.0 * n_tup_hot_upd / nullif(n_tup_upd, 0), 1) as hot_pct
from pg_stat_user_tables
where n_tup_upd > 1000
order by n_tup_upd desc;

Troubleshooting​

Metrics show stale values​

Table statistics are cumulative since last stats reset:

select stats_reset from pg_stat_database where datname = current_database();

Size metrics not matching disk​

pg_table_size excludes TOAST and indexes. Use pg_total_relation_size for complete size.

Missing tables in metrics​

Verify tables are in user schemas (not system catalogs):

select relname from pg_stat_user_tables where schemaname = 'public';