From: Tom Lane Date: Wed, 7 Feb 2007 23:11:30 +0000 (+0000) Subject: Add a function pg_stat_clear_snapshot() that discards any statistics snapshot X-Git-Tag: REL8_3_BETA1~1291 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aec4cf1c8c410f9c9db3deabcb94502dcd355b3f;p=postgresql Add a function pg_stat_clear_snapshot() that discards any statistics snapshot already collected in the current transaction; this allows plpgsql functions to watch for stats updates even though they are confined to a single transaction. Use this instead of the previous kluge involving pg_stat_file() to wait for the stats collector to update in the stats regression test. Internally, decouple storage of stats snapshots from transaction boundaries; they'll now stick around until someone calls pgstat_clear_snapshot --- which xact.c still does at transaction end, to maintain the previous behavior. This makes the logic a lot cleaner, at the price of a couple dozen cycles per transaction exit. --- diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 54adf3990b..4a9732fc39 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -1,4 +1,4 @@ - + Monitoring Database Activity @@ -227,7 +227,10 @@ postgres: user database host pg_stat_clear_snapshot(), which will discard the + current transaction's statistics snapshot (if any). The next use of + statistical information will cause a new snapshot to be fetched. @@ -707,11 +710,20 @@ postgres: user database host + + pg_stat_clear_snapshot() + void + + Discard the current statistics snapshot + + + pg_stat_reset() - boolean + void - Reset all block-level and row-level statistics to zero + Reset all statistics counters for the current database to zero + (requires superuser privileges) diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 4ee1cc711c..26a3c5ddc2 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.232 2007/02/01 19:10:25 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.233 2007/02/07 23:11:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1628,6 +1628,7 @@ CommitTransaction(void) AtEOXact_Namespace(true); /* smgrcommit already done */ AtEOXact_Files(); + pgstat_clear_snapshot(); pgstat_count_xact_commit(); pgstat_report_txn_timestamp(0); @@ -1844,6 +1845,7 @@ PrepareTransaction(void) AtEOXact_Namespace(true); /* smgrcommit already done */ AtEOXact_Files(); + pgstat_clear_snapshot(); CurrentResourceOwner = NULL; ResourceOwnerDelete(TopTransactionResourceOwner); @@ -1995,6 +1997,7 @@ AbortTransaction(void) AtEOXact_Namespace(false); smgrabort(); AtEOXact_Files(); + pgstat_clear_snapshot(); pgstat_count_xact_rollback(); pgstat_report_txn_timestamp(0); diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 6a5907c466..f64e02020a 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2007, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.144 2007/01/26 20:06:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.145 2007/02/07 23:11:29 tgl Exp $ * ---------- */ #include "postgres.h" @@ -130,9 +130,8 @@ static TabStatArray SharedTabStat = {0, 0, NULL}; static int pgStatXactCommit = 0; static int pgStatXactRollback = 0; -static TransactionId pgStatDBHashXact = InvalidTransactionId; +static MemoryContext pgStatLocalContext = NULL; static HTAB *pgStatDBHash = NULL; -static TransactionId pgStatLocalStatusXact = InvalidTransactionId; static PgBackendStatus *localBackendStatusTable = NULL; static int localNumBackends = 0; @@ -156,11 +155,13 @@ static void pgstat_beshutdown_hook(int code, Datum arg); static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create); static void pgstat_drop_database(Oid databaseid); static void pgstat_write_statsfile(void); -static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb); +static HTAB *pgstat_read_statsfile(Oid onlydb); static void backend_read_statsfile(void); static void pgstat_read_current_status(void); static HTAB *pgstat_collect_oids(Oid catalogid); +static void pgstat_setup_memcxt(void); + static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype); static void pgstat_send(void *msg, int len); @@ -1535,22 +1536,24 @@ pgstat_report_waiting(bool waiting) static void pgstat_read_current_status(void) { - TransactionId topXid = GetTopTransactionId(); volatile PgBackendStatus *beentry; + PgBackendStatus *localtable; PgBackendStatus *localentry; int i; Assert(!pgStatRunningInCollector); - if (TransactionIdEquals(pgStatLocalStatusXact, topXid)) + if (localBackendStatusTable) return; /* already done */ - localBackendStatusTable = (PgBackendStatus *) - MemoryContextAlloc(TopTransactionContext, + pgstat_setup_memcxt(); + + localtable = (PgBackendStatus *) + MemoryContextAlloc(pgStatLocalContext, sizeof(PgBackendStatus) * MaxBackends); localNumBackends = 0; beentry = BackendStatusArray; - localentry = localBackendStatusTable; + localentry = localtable; for (i = 1; i <= MaxBackends; i++) { /* @@ -1587,7 +1590,8 @@ pgstat_read_current_status(void) } } - pgStatLocalStatusXact = topXid; + /* Set the pointer only after completion of a valid table */ + localBackendStatusTable = localtable; } @@ -1720,7 +1724,7 @@ PgstatCollectorMain(int argc, char *argv[]) * zero. */ pgStatRunningInCollector = true; - pgstat_read_statsfile(&pgStatDBHash, InvalidOid); + pgStatDBHash = pgstat_read_statsfile(InvalidOid); /* * Setup the descriptor set for select(2). Since only one bit in the set @@ -2090,38 +2094,24 @@ pgstat_write_statsfile(void) * databases' hash table (whose entries point to the tables' hash tables). * ---------- */ -static void -pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) +static HTAB * +pgstat_read_statsfile(Oid onlydb) { PgStat_StatDBEntry *dbentry; PgStat_StatDBEntry dbbuf; PgStat_StatTabEntry *tabentry; PgStat_StatTabEntry tabbuf; HASHCTL hash_ctl; + HTAB *dbhash; HTAB *tabhash = NULL; FILE *fpin; int32 format_id; bool found; - MemoryContext use_mcxt; - int mcxt_flags; /* - * If running in the collector or the autovacuum process, we use the - * DynaHashCxt memory context. If running in a backend, we use the - * TopTransactionContext instead, so the caller must only know the last - * XactId when this call happened to know if his tables are still valid or - * already gone! + * The tables will live in pgStatLocalContext. */ - if (pgStatRunningInCollector || IsAutoVacuumProcess()) - { - use_mcxt = NULL; - mcxt_flags = 0; - } - else - { - use_mcxt = TopTransactionContext; - mcxt_flags = HASH_CONTEXT; - } + pgstat_setup_memcxt(); /* * Create the DB hashtable @@ -2130,9 +2120,9 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) hash_ctl.keysize = sizeof(Oid); hash_ctl.entrysize = sizeof(PgStat_StatDBEntry); hash_ctl.hash = oid_hash; - hash_ctl.hcxt = use_mcxt; - *dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl, - HASH_ELEM | HASH_FUNCTION | mcxt_flags); + hash_ctl.hcxt = pgStatLocalContext; + dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl, + HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT); /* * Try to open the status file. If it doesn't exist, the backends simply @@ -2140,7 +2130,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) * with empty counters. */ if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL) - return; + return dbhash; /* * Verify it's of the expected format. @@ -2178,7 +2168,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) /* * Add to the DB hash */ - dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash, + dbentry = (PgStat_StatDBEntry *) hash_search(dbhash, (void *) &dbbuf.databaseid, HASH_ENTER, &found); @@ -2207,11 +2197,11 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) hash_ctl.keysize = sizeof(Oid); hash_ctl.entrysize = sizeof(PgStat_StatTabEntry); hash_ctl.hash = oid_hash; - hash_ctl.hcxt = use_mcxt; + hash_ctl.hcxt = pgStatLocalContext; dbentry->tables = hash_create("Per-database table", PGSTAT_TAB_HASH_SIZE, &hash_ctl, - HASH_ELEM | HASH_FUNCTION | mcxt_flags); + HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT); /* * Arrange that following 'T's add entries to this database's @@ -2274,44 +2264,78 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) done: FreeFile(fpin); + + return dbhash; } /* - * If not done for this transaction, read the statistics collector - * stats file into some hash tables. - * - * Because we store the tables in TopTransactionContext, the result - * is good for the entire current main transaction. - * - * Inside the autovacuum process, the statfile is assumed to be valid - * "forever", that is one iteration, within one database. This means - * we only consider the statistics as they were when the autovacuum - * iteration started. + * If not already done, read the statistics collector stats file into + * some hash tables. The results will be kept until pgstat_clear_snapshot() + * is called (typically, at end of transaction). */ static void backend_read_statsfile(void) { + /* already read it? */ + if (pgStatDBHash) + return; + Assert(!pgStatRunningInCollector); + + /* Autovacuum wants stats about all databases */ if (IsAutoVacuumProcess()) - { - /* already read it? */ - if (pgStatDBHash) - return; - Assert(!pgStatRunningInCollector); - pgstat_read_statsfile(&pgStatDBHash, InvalidOid); - } + pgStatDBHash = pgstat_read_statsfile(InvalidOid); else - { - TransactionId topXid = GetTopTransactionId(); + pgStatDBHash = pgstat_read_statsfile(MyDatabaseId); +} - if (!TransactionIdEquals(pgStatDBHashXact, topXid)) - { - Assert(!pgStatRunningInCollector); - pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId); - pgStatDBHashXact = topXid; - } - } + +/* ---------- + * pgstat_setup_memcxt() - + * + * Create pgStatLocalContext, if not already done. + * ---------- + */ +static void +pgstat_setup_memcxt(void) +{ + if (!pgStatLocalContext) + pgStatLocalContext = AllocSetContextCreate(TopMemoryContext, + "Statistics snapshot", + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); } + +/* ---------- + * pgstat_clear_snapshot() - + * + * Discard any data collected in the current transaction. Any subsequent + * request will cause new snapshots to be read. + * + * This is also invoked during transaction commit or abort to discard + * the no-longer-wanted snapshot. + * ---------- + */ +void +pgstat_clear_snapshot(void) +{ + /* In an autovacuum process we keep the stats forever */ + if (IsAutoVacuumProcess()) + return; + + /* Release memory, if any was allocated */ + if (pgStatLocalContext) + MemoryContextDelete(pgStatLocalContext); + + /* Reset variables */ + pgStatLocalContext = NULL; + pgStatDBHash = NULL; + localBackendStatusTable = NULL; + localNumBackends = 0; +} + + /* ---------- * pgstat_recv_tabstat() - * diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 94631969d0..d011fff76f 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.37 2007/01/05 22:19:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.38 2007/02/07 23:11:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,7 +39,6 @@ extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS); extern Datum pg_backend_pid(PG_FUNCTION_ARGS); -extern Datum pg_stat_reset(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS); @@ -57,6 +56,9 @@ extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS); extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS); extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS); +extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS); +extern Datum pg_stat_reset(PG_FUNCTION_ARGS); + Datum pg_stat_get_numscans(PG_FUNCTION_ARGS) @@ -336,16 +338,6 @@ pg_backend_pid(PG_FUNCTION_ARGS) PG_RETURN_INT32(MyProcPid); } -/* - * Built-in function for resetting the counters - */ -Datum -pg_stat_reset(PG_FUNCTION_ARGS) -{ - pgstat_reset_counters(); - - PG_RETURN_BOOL(true); -} Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS) @@ -678,3 +670,23 @@ pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } + + +/* Discard the active statistics snapshot */ +Datum +pg_stat_clear_snapshot(PG_FUNCTION_ARGS) +{ + pgstat_clear_snapshot(); + + PG_RETURN_VOID(); +} + + +/* Reset all counters for the current database */ +Datum +pg_stat_reset(PG_FUNCTION_ARGS) +{ + pgstat_reset_counters(); + + PG_RETURN_VOID(); +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 154b56b32d..9ebc4e9b9f 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.381 2007/02/06 02:59:12 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.382 2007/02/07 23:11:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200702051 +#define CATALOG_VERSION_NO 200702071 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 500d239542..e8014c2bda 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.442 2007/02/03 14:06:55 petere Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.443 2007/02/07 23:11:30 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2938,8 +2938,6 @@ DATA(insert OID = 1936 ( pg_stat_get_backend_idset PGNSP PGUID 12 1 100 f f t DESCR("Statistics: Currently active backend IDs"); DATA(insert OID = 2026 ( pg_backend_pid PGNSP PGUID 12 1 0 f f t f s 0 23 "" _null_ _null_ _null_ pg_backend_pid - _null_ )); DESCR("Statistics: Current backend PID"); -DATA(insert OID = 2274 ( pg_stat_reset PGNSP PGUID 12 1 0 f f f f v 0 16 "" _null_ _null_ _null_ pg_stat_reset - _null_ )); -DESCR("Statistics: Reset collected statistics"); DATA(insert OID = 1937 ( pg_stat_get_backend_pid PGNSP PGUID 12 1 0 f f t f s 1 23 "23" _null_ _null_ _null_ pg_stat_get_backend_pid - _null_ )); DESCR("Statistics: PID of backend"); DATA(insert OID = 1938 ( pg_stat_get_backend_dbid PGNSP PGUID 12 1 0 f f t f s 1 26 "23" _null_ _null_ _null_ pg_stat_get_backend_dbid - _null_ )); @@ -2970,6 +2968,10 @@ DATA(insert OID = 1944 ( pg_stat_get_db_blocks_fetched PGNSP PGUID 12 1 0 f f t DESCR("Statistics: Blocks fetched for database"); DATA(insert OID = 1945 ( pg_stat_get_db_blocks_hit PGNSP PGUID 12 1 0 f f t f s 1 20 "26" _null_ _null_ _null_ pg_stat_get_db_blocks_hit - _null_ )); DESCR("Statistics: Blocks found in cache for database"); +DATA(insert OID = 2230 ( pg_stat_clear_snapshot PGNSP PGUID 12 1 0 f f f f v 0 2278 "" _null_ _null_ _null_ pg_stat_clear_snapshot - _null_ )); +DESCR("Statistics: Discard current transaction's statistics snapshot"); +DATA(insert OID = 2274 ( pg_stat_reset PGNSP PGUID 12 1 0 f f f f v 0 2278 "" _null_ _null_ _null_ pg_stat_reset - _null_ )); +DESCR("Statistics: Reset collected statistics for current database"); DATA(insert OID = 1946 ( encode PGNSP PGUID 12 1 0 f f t f i 2 25 "17 25" _null_ _null_ _null_ binary_encode - _null_ )); DESCR("Convert bytea value into some ascii-only text string"); diff --git a/src/include/pgstat.h b/src/include/pgstat.h index e64fb8bf55..896cc5ad68 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -5,7 +5,7 @@ * * Copyright (c) 2001-2007, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.52 2007/01/05 22:19:50 momjian Exp $ + * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.53 2007/02/07 23:11:30 tgl Exp $ * ---------- */ #ifndef PGSTAT_H @@ -380,6 +380,7 @@ extern void pgstat_report_tabstat(void); extern void pgstat_vacuum_tabstat(void); extern void pgstat_drop_relation(Oid relid); +extern void pgstat_clear_snapshot(void); extern void pgstat_reset_counters(void); extern void pgstat_report_autovac(Oid dboid); diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out index d6b17157b0..fc76d14225 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -27,61 +27,28 @@ SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, FROM pg_catalog.pg_stat_user_tables AS t, pg_catalog.pg_statio_user_tables AS b WHERE t.relname='tenk2' AND b.relname='tenk2'; --- enable statistics -SET stats_block_level = on; -SET stats_row_level = on; --- do a seqscan -SELECT count(*) FROM tenk2; - count -------- - 10000 -(1 row) - --- do an indexscan -SELECT count(*) FROM tenk2 WHERE unique1 = 1; - count -------- - 1 -(1 row) - --- All of the thrashing here is to wait for the stats collector to update, --- without waiting too long (in fact, we'd like to try to measure how long --- we wait). Watching for change in the stats themselves wouldn't work --- because the backend only reads them once per transaction. The stats file --- mod timestamp isn't too helpful because it may have resolution of only one --- second, or even worse. So, we touch a new table and then watch for change --- in the size of the stats file. Ugh. --- save current stats-file size -CREATE TEMP TABLE prevfilesize AS - SELECT size FROM pg_stat_file('global/pgstat.stat'); --- make and touch a previously nonexistent table -CREATE TABLE stats_hack (f1 int); -SELECT * FROM stats_hack; - f1 ----- -(0 rows) - --- wait for stats collector to update +-- function to wait for counters to advance create function wait_for_stats() returns void as $$ declare start_time timestamptz := clock_timestamp(); - oldsize bigint; - newsize bigint; + updated bool; begin - -- fetch previous stats-file size - select size into oldsize from prevfilesize; - -- we don't want to wait forever; loop will exit after 30 seconds for i in 1 .. 300 loop - -- look for update of stats file - select size into newsize from pg_stat_file('global/pgstat.stat'); + -- check to see if indexscan has been sensed + SELECT (st.idx_scan >= pr.idx_scan + 1) INTO updated + FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + WHERE st.relname='tenk2' AND cl.relname='tenk2'; - exit when newsize != oldsize; + exit when updated; -- wait a little perform pg_sleep(0.1); + -- reset stats snapshot so we can test again + perform pg_stat_clear_snapshot(); + end loop; -- report time waited in postmaster log (where it won't change test output) @@ -89,13 +56,30 @@ begin extract(epoch from clock_timestamp() - start_time); end $$ language plpgsql; +-- enable statistics +SET stats_block_level = on; +SET stats_row_level = on; +-- do a seqscan +SELECT count(*) FROM tenk2; + count +------- + 10000 +(1 row) + +-- do an indexscan +SELECT count(*) FROM tenk2 WHERE unique1 = 1; + count +------- + 1 +(1 row) + +-- wait for stats collector to update SELECT wait_for_stats(); wait_for_stats ---------------- (1 row) -DROP TABLE stats_hack; -- check effects SELECT st.seq_scan >= pr.seq_scan + 1, st.seq_tup_read >= pr.seq_tup_read + cl.reltuples, diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql index dca0031470..cde38b3a37 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -21,52 +21,28 @@ SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, pg_catalog.pg_statio_user_tables AS b WHERE t.relname='tenk2' AND b.relname='tenk2'; --- enable statistics -SET stats_block_level = on; -SET stats_row_level = on; - --- do a seqscan -SELECT count(*) FROM tenk2; --- do an indexscan -SELECT count(*) FROM tenk2 WHERE unique1 = 1; - --- All of the thrashing here is to wait for the stats collector to update, --- without waiting too long (in fact, we'd like to try to measure how long --- we wait). Watching for change in the stats themselves wouldn't work --- because the backend only reads them once per transaction. The stats file --- mod timestamp isn't too helpful because it may have resolution of only one --- second, or even worse. So, we touch a new table and then watch for change --- in the size of the stats file. Ugh. - --- save current stats-file size -CREATE TEMP TABLE prevfilesize AS - SELECT size FROM pg_stat_file('global/pgstat.stat'); - --- make and touch a previously nonexistent table -CREATE TABLE stats_hack (f1 int); -SELECT * FROM stats_hack; - --- wait for stats collector to update +-- function to wait for counters to advance create function wait_for_stats() returns void as $$ declare start_time timestamptz := clock_timestamp(); - oldsize bigint; - newsize bigint; + updated bool; begin - -- fetch previous stats-file size - select size into oldsize from prevfilesize; - -- we don't want to wait forever; loop will exit after 30 seconds for i in 1 .. 300 loop - -- look for update of stats file - select size into newsize from pg_stat_file('global/pgstat.stat'); + -- check to see if indexscan has been sensed + SELECT (st.idx_scan >= pr.idx_scan + 1) INTO updated + FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + WHERE st.relname='tenk2' AND cl.relname='tenk2'; - exit when newsize != oldsize; + exit when updated; -- wait a little perform pg_sleep(0.1); + -- reset stats snapshot so we can test again + perform pg_stat_clear_snapshot(); + end loop; -- report time waited in postmaster log (where it won't change test output) @@ -75,9 +51,17 @@ begin end $$ language plpgsql; -SELECT wait_for_stats(); +-- enable statistics +SET stats_block_level = on; +SET stats_row_level = on; -DROP TABLE stats_hack; +-- do a seqscan +SELECT count(*) FROM tenk2; +-- do an indexscan +SELECT count(*) FROM tenk2 WHERE unique1 = 1; + +-- wait for stats collector to update +SELECT wait_for_stats(); -- check effects SELECT st.seq_scan >= pr.seq_scan + 1,