Remove pgstat's discrimination against MsgVacuum and MsgAnalyze messages.

Formerly, these message types would be discarded unless there was already
a stats hash table entry for the target table.  However, the intent of
saving hash table space for unused tables was subverted by the fact that
the physical I/O done by the vacuum or analyze would result in an immediately
following tabstat message, which would create the hash table entry anyway.
All that we had left was surprising loss of statistical data, as in a recent
complaint from Jaime Casanova.

It seems unlikely that a real database would have many tables that go totally
untouched over the long haul, so the consensus is that this "optimization"
serves little purpose anyhow.  Remove it, and just create the hash table
entry on demand in all cases.
This commit is contained in:
Tom Lane 2009-09-04 22:32:33 +00:00
parent 7be39bb0be
commit 47ef623c0b

View File

@ -13,7 +13,7 @@
*
* Copyright (c) 2001-2009, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.190 2009/08/12 20:53:30 tgl Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.191 2009/09/04 22:32:33 tgl Exp $
* ----------
*/
#include "postgres.h"
@ -246,6 +246,8 @@ static void pgstat_beshutdown_hook(int code, Datum arg);
static void pgstat_sighup_handler(SIGNAL_ARGS);
static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create);
static PgStat_StatTabEntry *pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry,
Oid tableoid, bool create);
static void pgstat_write_statsfile(bool permanent);
static HTAB *pgstat_read_statsfile(Oid onlydb, bool permanent);
static void backend_read_statsfile(void);
@ -2940,6 +2942,52 @@ pgstat_get_db_entry(Oid databaseid, bool create)
}
/*
* Lookup the hash table entry for the specified table. If no hash
* table entry exists, initialize it, if the create parameter is true.
* Else, return NULL.
*/
static PgStat_StatTabEntry *
pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create)
{
PgStat_StatTabEntry *result;
bool found;
HASHACTION action = (create ? HASH_ENTER : HASH_FIND);
/* Lookup or create the hash table entry for this table */
result = (PgStat_StatTabEntry *) hash_search(dbentry->tables,
&tableoid,
action, &found);
if (!create && !found)
return NULL;
/* If not found, initialize the new one. */
if (!found)
{
result->numscans = 0;
result->tuples_returned = 0;
result->tuples_fetched = 0;
result->tuples_inserted = 0;
result->tuples_updated = 0;
result->tuples_deleted = 0;
result->tuples_hot_updated = 0;
result->n_live_tuples = 0;
result->n_dead_tuples = 0;
result->last_anl_tuples = 0;
result->blocks_fetched = 0;
result->blocks_hit = 0;
result->vacuum_timestamp = 0;
result->autovac_vacuum_timestamp = 0;
result->analyze_timestamp = 0;
result->autovac_analyze_timestamp = 0;
}
return result;
}
/* ----------
* pgstat_write_statsfile() -
*
@ -3553,10 +3601,10 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
tabentry->tuples_hot_updated = tabmsg[i].t_counts.t_tuples_hot_updated;
tabentry->n_live_tuples = tabmsg[i].t_counts.t_new_live_tuples;
tabentry->n_dead_tuples = tabmsg[i].t_counts.t_new_dead_tuples;
tabentry->last_anl_tuples = 0;
tabentry->blocks_fetched = tabmsg[i].t_counts.t_blocks_fetched;
tabentry->blocks_hit = tabmsg[i].t_counts.t_blocks_hit;
tabentry->last_anl_tuples = 0;
tabentry->vacuum_timestamp = 0;
tabentry->autovac_vacuum_timestamp = 0;
tabentry->analyze_timestamp = 0;
@ -3734,19 +3782,10 @@ pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len)
PgStat_StatDBEntry *dbentry;
/*
* Lookup the database in the hashtable. Don't create the entry if it
* doesn't exist, because autovacuum may be processing a template
* database. If this isn't the case, the database is most likely to have
* an entry already. (If it doesn't, not much harm is done anyway --
* it'll get created as soon as somebody actually uses the database.)
* Store the last autovacuum time in the database's hashtable entry.
*/
dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
if (dbentry == NULL)
return;
dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
/*
* Store the last autovacuum time in the database entry.
*/
dbentry->last_autovac_time = msg->m_start_time;
}
@ -3763,18 +3802,11 @@ pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
PgStat_StatTabEntry *tabentry;
/*
* Don't create either the database or table entry if it doesn't already
* exist. This avoids bloating the stats with entries for stuff that is
* only touched by vacuum and not by live operations.
* Store the data in the table's hashtable entry.
*/
dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
if (dbentry == NULL)
return;
dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
HASH_FIND, NULL);
if (tabentry == NULL)
return;
tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid, true);
if (msg->m_autovacuum)
tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime;
@ -3821,18 +3853,11 @@ pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
PgStat_StatTabEntry *tabentry;
/*
* Don't create either the database or table entry if it doesn't already
* exist. This avoids bloating the stats with entries for stuff that is
* only touched by analyze and not by live operations.
* Store the data in the table's hashtable entry.
*/
dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
if (dbentry == NULL)
return;
dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
HASH_FIND, NULL);
if (tabentry == NULL)
return;
tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid, true);
if (msg->m_autovacuum)
tabentry->autovac_analyze_timestamp = msg->m_analyzetime;