On 6.4.2013 21:51, Tomas Vondra wrote: > Hi, > > I'm regularly using pg_stat_database view to analyze various aspects of > behavior of the cluster. The #1 issue I'm constantly running into is > that to get cluster-level view (across all the databases), the table > needs to be aggregated like this: > > SELECT > SUM(blks_hit) blks_hit, > SUM(blks_read) blks_read > FROM pg_stat_database > > This more or less works in stable environments, but once you start > dropping databases (think of hosting with shared DB server) it gets > unusable because after DROP DATABASE the database suddenly disappears > from the sum. > > Therefore I do propose tracking the aggregated stats, similar to the > pg_stat_bgwriter view. This does not require new messages (thanks to > reuse of the existing messages), and I expect the overhead to be > negligible (a few bytes of storage, minimal CPU). > > I think it does not make sense to merge this into pg_stat_bgwriter, > creating a new view (can't think of a good name though), seems like a > much better choice to me.
Attached is a first version of the patch, just to illustrate the idea. It creates a new system view pg_stat_agg_database with aggregated data. There are no docs, no regression tests etc. Now, I'm thinking if we should do something similar with database object (table/index) stats, i.e. keep maintain aggregated data. This might seem silly at first, but consider for example a partitioned table. It's common to have a db-level metrics on idx/seq_scans, but when you drop a partition (e.g. the oldest one), you may get into the same trouble as with database stats (see my previous post). So I think it would be handy to define table/index stats aggregated at the db-level, i.e. there would be one row for each database. I don't think it makes much sense to aggregate vacuum/analyze info (counts and timestamps), which means 18 BIGINT counters from pg_stat[io]_tables, and 10 BIGINT counters from pg_stat[io]_indexes. That's 224B for each database, which I believe is negligible. OTOH it would be very handy to have this info aggretated per-schema and per-tablespace, but I'd say to do that later in a separate patch. Opinions? Tomas
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 57adbf6..28f3ca2 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -636,6 +636,27 @@ CREATE VIEW pg_stat_database AS pg_stat_get_db_stat_reset_time(D.oid) AS stats_reset FROM pg_database D; +CREATE VIEW pg_stat_agg_database AS + SELECT + pg_stat_get_all_numbackends() AS numbackends, + pg_stat_get_all_xact_commit() AS xact_commit, + pg_stat_get_all_xact_rollback() AS xact_rollback, + pg_stat_get_all_blocks_fetched() - + pg_stat_get_all_blocks_hit() AS blks_read, + pg_stat_get_all_blocks_hit() AS blks_hit, + pg_stat_get_all_tuples_returned() AS tup_returned, + pg_stat_get_all_tuples_fetched() AS tup_fetched, + pg_stat_get_all_tuples_inserted() AS tup_inserted, + pg_stat_get_all_tuples_updated() AS tup_updated, + pg_stat_get_all_tuples_deleted() AS tup_deleted, + pg_stat_get_all_conflict_all() AS conflicts, + pg_stat_get_all_temp_files() AS temp_files, + pg_stat_get_all_temp_bytes() AS temp_bytes, + pg_stat_get_all_deadlocks() AS deadlocks, + pg_stat_get_all_blk_read_time() AS blk_read_time, + pg_stat_get_all_blk_write_time() AS blk_write_time, + pg_stat_get_bgwriter_stat_reset_time() AS stats_reset; + CREATE VIEW pg_stat_database_conflicts AS SELECT D.oid AS datid, diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 29d986a..121794d 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -4478,6 +4478,12 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) int i; bool found; + /* update aggregated data first */ + globalStats.n_xact_commit += (PgStat_Counter) (msg->m_xact_commit); + globalStats.n_xact_rollback += (PgStat_Counter) (msg->m_xact_rollback); + globalStats.n_block_read_time += msg->m_block_read_time; + globalStats.n_block_write_time += msg->m_block_write_time; + dbentry = pgstat_get_db_entry(msg->m_databaseid, true); /* @@ -4561,6 +4567,15 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) dbentry->n_tuples_deleted += tabmsg->t_counts.t_tuples_deleted; dbentry->n_blocks_fetched += tabmsg->t_counts.t_blocks_fetched; dbentry->n_blocks_hit += tabmsg->t_counts.t_blocks_hit; + + /* update the aggregated counters too */ + globalStats.n_blocks_fetched += tabmsg->t_counts.t_blocks_fetched; + globalStats.n_blocks_hit += tabmsg->t_counts.t_blocks_hit; + globalStats.n_tuples_returned += tabmsg->t_counts.t_tuples_returned; + globalStats.n_tuples_fetched += tabmsg->t_counts.t_tuples_fetched; + globalStats.n_tuples_inserted += tabmsg->t_counts.t_tuples_inserted; + globalStats.n_tuples_updated += tabmsg->t_counts.t_tuples_updated; + globalStats.n_tuples_deleted += tabmsg->t_counts.t_tuples_deleted; } } @@ -4869,18 +4884,23 @@ pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len) break; case PROCSIG_RECOVERY_CONFLICT_TABLESPACE: dbentry->n_conflict_tablespace++; + globalStats.n_conflict_tablespace++; break; case PROCSIG_RECOVERY_CONFLICT_LOCK: dbentry->n_conflict_lock++; + globalStats.n_conflict_lock++; break; case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT: dbentry->n_conflict_snapshot++; + globalStats.n_conflict_snapshot++; break; case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN: dbentry->n_conflict_bufferpin++; + globalStats.n_conflict_bufferpin++; break; case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK: dbentry->n_conflict_startup_deadlock++; + globalStats.n_conflict_startup_deadlock++; break; } } @@ -4899,6 +4919,7 @@ pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len) dbentry = pgstat_get_db_entry(msg->m_databaseid, true); dbentry->n_deadlocks++; + globalStats.n_deadlocks++; } /* ---------- @@ -4916,6 +4937,9 @@ pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len) dbentry->n_temp_bytes += msg->m_filesize; dbentry->n_temp_files += 1; + + globalStats.n_temp_bytes += msg->m_filesize; + globalStats.n_temp_files += 1; } /* ---------- diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 8c1a767..f3fd59e 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -98,6 +98,28 @@ extern Datum pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS); extern Datum pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS); extern Datum pg_stat_get_buf_alloc(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_numbackends(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_xact_commit(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_xact_rollback(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_blocks_fetched(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_blocks_hit(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_tuples_returned(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_tuples_fetched(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_tuples_inserted(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_tuples_updated(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_tuples_deleted(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_conflict_tablespace(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_conflict_lock(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_conflict_snapshot(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_conflict_bufferpin(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_conflict_startup_deadlock(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_conflict_all(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_deadlocks(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_temp_files(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_temp_bytes(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_blk_read_time(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_all_blk_write_time(PG_FUNCTION_ARGS); + extern Datum pg_stat_get_xact_numscans(PG_FUNCTION_ARGS); extern Datum pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS); extern Datum pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS); @@ -1458,6 +1480,152 @@ pg_stat_get_buf_alloc(PG_FUNCTION_ARGS) } Datum +pg_stat_get_all_numbackends(PG_FUNCTION_ARGS) +{ + + int32 result; + int tot_backends = pgstat_fetch_stat_numbackends(); + int beid; + + result = 0; + for (beid = 1; beid <= tot_backends; beid++) + { + PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid); + if (beentry) + result++; + } + + PG_RETURN_INT32(result); + +} + +Datum +pg_stat_get_all_xact_commit(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_xact_commit); +} + +Datum +pg_stat_get_all_xact_rollback(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_xact_rollback); +} + +Datum +pg_stat_get_all_blocks_fetched(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_blocks_fetched); +} + +Datum +pg_stat_get_all_blocks_hit(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_blocks_hit); +} + +Datum +pg_stat_get_all_tuples_returned(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_tuples_returned); +} + +Datum +pg_stat_get_all_tuples_fetched(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_tuples_fetched); +} + +Datum +pg_stat_get_all_tuples_inserted(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_tuples_inserted); +} + +Datum +pg_stat_get_all_tuples_updated(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_tuples_updated); +} + +Datum +pg_stat_get_all_tuples_deleted(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_tuples_deleted); +} + +Datum +pg_stat_get_all_conflict_tablespace(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_conflict_tablespace); +} + +Datum +pg_stat_get_all_conflict_lock(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_conflict_lock); +} + +Datum +pg_stat_get_all_conflict_snapshot(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_conflict_snapshot); +} + +Datum +pg_stat_get_all_conflict_bufferpin(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_conflict_bufferpin); +} + +Datum +pg_stat_get_all_conflict_startup_deadlock(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_conflict_startup_deadlock); +} + +Datum +pg_stat_get_all_conflict_all(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64( + pgstat_fetch_global()->n_conflict_tablespace + + pgstat_fetch_global()->n_conflict_lock + + pgstat_fetch_global()->n_conflict_snapshot + + pgstat_fetch_global()->n_conflict_bufferpin + + pgstat_fetch_global()->n_conflict_bufferpin + ); +} + +Datum +pg_stat_get_all_deadlocks(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_deadlocks); +} + +Datum +pg_stat_get_all_temp_files(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_temp_files); +} + +Datum +pg_stat_get_all_temp_bytes(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->n_temp_bytes); +} + +Datum +pg_stat_get_all_blk_read_time(PG_FUNCTION_ARGS) +{ + PG_RETURN_FLOAT8(((double) pgstat_fetch_global()->n_block_read_time) / 1000.0); +} + +Datum +pg_stat_get_all_blk_write_time(PG_FUNCTION_ARGS) +{ + PG_RETURN_FLOAT8(((double) pgstat_fetch_global()->n_block_write_time) / 1000.0); +} + +Datum pg_stat_get_xact_numscans(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 4d5cd9f..5f91bf3 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -2710,6 +2710,50 @@ DESCR("statistics: number of backend buffer writes that did their own fsync"); DATA(insert OID = 2859 ( pg_stat_get_buf_alloc PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_buf_alloc _null_ _null_ _null_ )); DESCR("statistics: number of buffer allocations"); +DATA(insert OID = 3900 ( pg_stat_get_all_numbackends PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_numbackends _null_ _null_ _null_ )); +DESCR("statistics: transactions committed"); +DATA(insert OID = 2860 ( pg_stat_get_all_xact_commit PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_xact_commit _null_ _null_ _null_ )); +DESCR("statistics: transactions committed"); +DATA(insert OID = 2861 ( pg_stat_get_all_xact_rollback PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_xact_rollback _null_ _null_ _null_ )); +DESCR("statistics: transactions rolled back"); +DATA(insert OID = 2862 ( pg_stat_get_all_blocks_fetched PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_blocks_fetched _null_ _null_ _null_ )); +DESCR("statistics: blocks fetched"); +DATA(insert OID = 2863 ( pg_stat_get_all_blocks_hit PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_blocks_hit _null_ _null_ _null_ )); +DESCR("statistics: blocks found in cache"); +DATA(insert OID = 2864 ( pg_stat_get_all_tuples_returned PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_tuples_returned _null_ _null_ _null_ )); +DESCR("statistics: tuples returned"); +DATA(insert OID = 2865 ( pg_stat_get_all_tuples_fetched PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_tuples_fetched _null_ _null_ _null_ )); +DESCR("statistics: tuples fetched"); +DATA(insert OID = 2866 ( pg_stat_get_all_tuples_inserted PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_tuples_inserted _null_ _null_ _null_ )); +DESCR("statistics: tuples inserted"); +DATA(insert OID = 2867 ( pg_stat_get_all_tuples_updated PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_tuples_updated _null_ _null_ _null_ )); +DESCR("statistics: tuples updated"); +DATA(insert OID = 2868 ( pg_stat_get_all_tuples_deleted PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_tuples_deleted _null_ _null_ _null_ )); +DESCR("statistics: tuples deleted"); +DATA(insert OID = 2869 ( pg_stat_get_all_conflict_tablespace PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_conflict_tablespace _null_ _null_ _null_ )); +DESCR("statistics: recovery conflicts caused by drop tablespace"); +DATA(insert OID = 2870 ( pg_stat_get_all_conflict_lock PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_conflict_lock _null_ _null_ _null_ )); +DESCR("statistics: recovery conflicts caused by relation lock"); +DATA(insert OID = 2871 ( pg_stat_get_all_conflict_snapshot PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_conflict_snapshot _null_ _null_ _null_ )); +DESCR("statistics: recovery conflicts caused by snapshot expiry"); +DATA(insert OID = 2872 ( pg_stat_get_all_conflict_bufferpin PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_conflict_bufferpin _null_ _null_ _null_ )); +DESCR("statistics: recovery conflicts caused by shared buffer pin"); +DATA(insert OID = 2873 ( pg_stat_get_all_conflict_startup_deadlock PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_conflict_startup_deadlock _null_ _null_ _null_ )); +DESCR("statistics: recovery conflicts caused by buffer deadlock"); +DATA(insert OID = 2874 ( pg_stat_get_all_conflict_all PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_conflict_all _null_ _null_ _null_ )); +DESCR("statistics: recovery conflicts"); +DATA(insert OID = 2875 ( pg_stat_get_all_deadlocks PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_deadlocks _null_ _null_ _null_ )); +DESCR("statistics: deadlocks detected"); + +DATA(insert OID = 2876 ( pg_stat_get_all_temp_files PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_temp_files _null_ _null_ _null_ )); +DESCR("statistics: number of temporary files written"); +DATA(insert OID = 2877 ( pg_stat_get_all_temp_bytes PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_all_temp_bytes _null_ _null_ _null_ )); +DESCR("statistics: number of bytes in temporary files written"); +DATA(insert OID = 2976 ( pg_stat_get_all_blk_read_time PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 701 "" _null_ _null_ _null_ _null_ pg_stat_get_all_blk_read_time _null_ _null_ _null_ )); +DESCR("statistics: block read time, in msec"); +DATA(insert OID = 2977 ( pg_stat_get_all_blk_write_time PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 701 "" _null_ _null_ _null_ _null_ pg_stat_get_all_blk_write_time _null_ _null_ _null_ )); +DESCR("statistics: block write time, in msec"); + DATA(insert OID = 2978 ( pg_stat_get_function_calls PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_function_calls _null_ _null_ _null_ )); DESCR("statistics: number of function calls"); DATA(insert OID = 2979 ( pg_stat_get_function_total_time PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 701 "26" _null_ _null_ _null_ _null_ pg_stat_get_function_total_time _null_ _null_ _null_ )); diff --git a/src/include/pgstat.h b/src/include/pgstat.h index fb242e4..1ff6e7d 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -624,6 +624,28 @@ typedef struct PgStat_GlobalStats PgStat_Counter buf_written_backend; PgStat_Counter buf_fsync_backend; PgStat_Counter buf_alloc; + + /* aggregated data from PgStat_StatDBEntry */ + PgStat_Counter n_xact_commit; + PgStat_Counter n_xact_rollback; + PgStat_Counter n_blocks_fetched; + PgStat_Counter n_blocks_hit; + PgStat_Counter n_tuples_returned; + PgStat_Counter n_tuples_fetched; + PgStat_Counter n_tuples_inserted; + PgStat_Counter n_tuples_updated; + PgStat_Counter n_tuples_deleted; + PgStat_Counter n_conflict_tablespace; + PgStat_Counter n_conflict_lock; + PgStat_Counter n_conflict_snapshot; + PgStat_Counter n_conflict_bufferpin; + PgStat_Counter n_conflict_startup_deadlock; + PgStat_Counter n_temp_files; + PgStat_Counter n_temp_bytes; + PgStat_Counter n_deadlocks; + PgStat_Counter n_block_read_time; /* times in microseconds */ + PgStat_Counter n_block_write_time; + TimestampTz stat_reset_timestamp; } PgStat_GlobalStats;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers