From b0ef2a51121ee257d282c808a0900d4978adcda3 Mon Sep 17 00:00:00 2001 From: Isaac Seymour Date: Wed, 18 Aug 2021 13:19:37 +0100 Subject: [PATCH] Add metrics from pg_stat_user_indexes Helps with identifying unused or under-used indexes --- README.md | 6 ++ collector/exporter.go | 1 + collector/stat_user_indexes.go | 103 +++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 collector/stat_user_indexes.go diff --git a/README.md b/README.md index 27ab4944..44f7229a 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,10 @@ Prometheus exporter for PostgreSQL server metrics. - stat_archiver - stat_bgwriter - stat_database +- stat_progress_vacuum - stat_replication +- stat_user_indexes +- stat_user_tables - info - locks @@ -69,6 +72,9 @@ Prometheus exporter for PostgreSQL server metrics. | postgres_stat_vacuum_progress_phase_vacuuming_heap | VACUUM is currently vacuuming the heap | pid, query_start, schemaname, datname, relname | | postgres_stat_vacuum_progress_phase_vacuuming_indexes | VACUUM is currently vacuuming the indexes | pid, query_start, schemaname, datname, relname | | postgres_stat_vacuum_progress_running | VACUUM is running | pid, query_start, schemaname, datname, relname | +| postgres_stat_user_indexes_scan_total | Number of times this index has been scanned | datname, schemaname, tablename, indexname | +| postgres_stat_user_indexes_tuple_read_total | Number of times tuples have been returned from scanning this index | datname, schemaname, tablename, indexname | +| postgres_stat_user_indexes_tuple_fetch_total | Number of live tuples fetched by scans on this index | datname, schemaname, tablename, indexname | | postgres_up | Whether the Postgres server is up | | ### Run diff --git a/collector/exporter.go b/collector/exporter.go index b157456c..4a489f2c 100644 --- a/collector/exporter.go +++ b/collector/exporter.go @@ -103,6 +103,7 @@ func NewExporter(ctx context.Context, logger kitlog.Logger, connConfig *pgx.Conn datnameScrapers: []Scraper{ NewStatVacuumProgressScraper(), NewStatUserTablesScraper(), + NewStatUserIndexesScraper(), NewDiskUsageScraper(), }, } diff --git a/collector/stat_user_indexes.go b/collector/stat_user_indexes.go new file mode 100644 index 00000000..469e582a --- /dev/null +++ b/collector/stat_user_indexes.go @@ -0,0 +1,103 @@ +package collector + +import ( + "context" + + pgx "github.com/jackc/pgx/v4" + "github.com/prometheus/client_golang/prometheus" +) + +// The Statistics Scraper +// PostgreSQL's statistics collector is a subsystem that supports collection and reporting of information about +// server activity. Presently, the collector can count accesses to tables and indexes in both disk-block and +// individual-row terms. It also tracks the total number of rows in each table, and information about vacuum +// and analyze actions for each table. It can also count calls to user-defined functions and the total time +// spent in each one. +//https://www.postgresql.org/docs/9.4/static/monitoring-stats.html#PG-STAT-ALL-INDEXES-VIEW +const ( + // Scrape query + statUserIndexesQuery = ` +SELECT schemaname + , relname + , indexrelname + , idx_scan::float + , idx_tup_read::float + , idx_tup_fetch::float + FROM pg_stat_user_indexes + WHERE schemaname != 'information_schema' + AND idx_tup_fetch IS NOT NULL /*postgres_exporter*/` +) + +type statUserIndexesScraper struct { + idxScan *prometheus.Desc + idxTupRead *prometheus.Desc + idxTupFetch *prometheus.Desc +} + +// NewStatUserIndexesScraper returns a new Scraper exposing postgres pg_stat_user_indexes view +func NewStatUserIndexesScraper() Scraper { + return &statUserIndexesScraper{ + idxScan: prometheus.NewDesc( + "postgres_stat_user_indexes_scan_total", + "Number of times this index has been scanned", + []string{"datname", "schemaname", "relname", "indexname"}, + nil, + ), + idxTupRead: prometheus.NewDesc( + "postgres_stat_user_indexes_tuple_read_total", + "Number of times tuples have been returned from scanning this index", + []string{"datname", "schemaname", "relname", "indexname"}, + nil, + ), + idxTupFetch: prometheus.NewDesc( + "postgres_stat_user_indexes_tuple_fetch_total", + "Number of live tuples fetched by scans on this index", + []string{"datname", "schemaname", "relname", "indexname"}, + nil, + ), + } +} + +func (c *statUserIndexesScraper) Name() string { + return "StatUserIndexesScraper" +} + +func (c *statUserIndexesScraper) Scrape(ctx context.Context, conn *pgx.Conn, version Version, ch chan<- prometheus.Metric) error { + var datname string + if err := conn.QueryRow(ctx, "SELECT current_database() /*postgres_exporter*/").Scan(&datname); err != nil { + return err + } + + rows, err := conn.Query(ctx, statUserIndexesQuery) + if err != nil { + return err + } + defer rows.Close() + + var schemaname, relname, indexname string + var idxScan, idxTupRead, idxTupFetch float64 + for rows.Next() { + if err := rows.Scan(&schemaname, + &relname, + &indexname, + &idxScan, + &idxTupRead, + &idxTupFetch); err != nil { + return err + } + + // postgres_stat_user_indexes_idx_scan_total + ch <- prometheus.MustNewConstMetric(c.idxScan, prometheus.CounterValue, idxScan, datname, schemaname, relname, indexname) + // postgres_stat_user_indexes_idx_tup_read_total + ch <- prometheus.MustNewConstMetric(c.idxTupRead, prometheus.CounterValue, idxTupRead, datname, schemaname, relname, indexname) + // postgres_stat_user_indexes_idx_tup_fetch_total + ch <- prometheus.MustNewConstMetric(c.idxTupFetch, prometheus.CounterValue, idxTupFetch, datname, schemaname, relname, indexname) + } + + err = rows.Err() + if err != nil { + return err + } + + return nil +}