From: Tom Lane Date: Wed, 30 Dec 2009 20:32:14 +0000 (+0000) Subject: Revise pgstat's tracking of tuple changes to improve the reliability of X-Git-Tag: REL9_0_ALPHA4~388 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=48c192c15e828812d62194126d869d0b104a4ef1;p=postgresql Revise pgstat's tracking of tuple changes to improve the reliability of decisions about when to auto-analyze. The previous code depended on n_live_tuples + n_dead_tuples - last_anl_tuples, where all three of these numbers could be bad estimates from ANALYZE itself. Even worse, in the presence of a steady flow of HOT updates and matching HOT-tuple reclamations, auto-analyze might never trigger at all, even if all three numbers are exactly right, because n_dead_tuples could hold steady. To fix, replace last_anl_tuples with an accurately tracked count of the total number of committed tuple inserts + updates + deletes since the last ANALYZE on the table. This can still be compared to the same threshold as before, but it's much more trustworthy than the old computation. Tracking this requires one more intra-transaction counter per modified table within backends, but no additional memory space in the stats collector. There probably isn't any measurable speed difference; if anything it might be a bit faster than before, since I was able to eliminate some per-tuple arithmetic operations in favor of adding sums once per (sub)transaction. Also, simplify the logic around pgstat vacuum and analyze reporting messages by not trying to fold VACUUM ANALYZE into a single pgstat message. The original thought behind this patch was to allow scheduling of analyzes on parent tables by artificially inflating their changes_since_analyze count. I've left that for a separate patch since this change seems to stand on its own merit. --- diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 0739db99f5..aa41cd3d4c 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.144 2009/12/29 20:11:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.145 2009/12/30 20:32:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -535,16 +535,13 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, } /* - * Update pages/tuples stats in pg_class. + * Update pages/tuples stats in pg_class, but not if we're inside a + * VACUUM that got a more precise number. */ if (update_reltuples) - { vac_update_relstats(onerel, RelationGetNumberOfBlocks(onerel), totalrows, hasindex, InvalidTransactionId); - /* report results to the stats collector, too */ - pgstat_report_analyze(onerel, totalrows, totaldeadrows); - } /* * Same for indexes. Vacuum always scans all indexes, so if we're part of @@ -565,6 +562,13 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, } } + /* + * Report ANALYZE to the stats collector, too; likewise, tell it to + * adopt these numbers only if we're not inside a VACUUM that got a + * better number. + */ + pgstat_report_analyze(onerel, update_reltuples, totalrows, totaldeadrows); + /* We skip to here if there were no analyzable columns */ cleanup: diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 0049b7c973..f43a74c475 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.400 2009/12/29 20:11:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.401 2009/12/30 20:32:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1332,7 +1332,6 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt) pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, true, - (vacstmt->options & VACOPT_ANALYZE) != 0, vacrelstats->rel_tuples); return heldoff; diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index acc6c42707..e899781cf6 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -29,7 +29,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.125 2009/12/19 01:32:34 sriggs Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.126 2009/12/30 20:32:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -237,7 +237,6 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, vacrelstats->scanned_all, - (vacstmt->options & VACOPT_ANALYZE) != 0, vacrelstats->rel_tuples); /* and log the action if appropriate */ diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index e4ab771b7f..0b30253c67 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -55,7 +55,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.105 2009/11/16 21:32:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.106 2009/12/30 20:32:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2591,8 +2591,7 @@ relation_needs_vacanalyze(Oid relid, { reltuples = classForm->reltuples; vactuples = tabentry->n_dead_tuples; - anltuples = tabentry->n_live_tuples + tabentry->n_dead_tuples - - tabentry->last_anl_tuples; + anltuples = tabentry->changes_since_analyze; vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples; anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples; diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index ab88a59eea..84fea02807 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2009, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.194 2009/12/27 19:40:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.195 2009/12/30 20:32:14 tgl Exp $ * ---------- */ #include "postgres.h" @@ -195,6 +195,7 @@ static int pgStatXactRollback = 0; typedef struct TwoPhasePgStatRecord { PgStat_Counter tuples_inserted; /* tuples inserted in xact */ + PgStat_Counter tuples_updated; /* tuples updated in xact */ PgStat_Counter tuples_deleted; /* tuples deleted in xact */ Oid t_id; /* table's OID */ bool t_shared; /* is it a shared catalog? */ @@ -1184,8 +1185,8 @@ pgstat_report_autovac(Oid dboid) * --------- */ void -pgstat_report_vacuum(Oid tableoid, bool shared, bool scanned_all, - bool analyze, PgStat_Counter tuples) +pgstat_report_vacuum(Oid tableoid, bool shared, bool adopt_counts, + PgStat_Counter tuples) { PgStat_MsgVacuum msg; @@ -1195,9 +1196,8 @@ pgstat_report_vacuum(Oid tableoid, bool shared, bool scanned_all, pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM); msg.m_databaseid = shared ? InvalidOid : MyDatabaseId; msg.m_tableoid = tableoid; - msg.m_scanned_all = scanned_all; - msg.m_analyze = analyze; - msg.m_autovacuum = IsAutoVacuumWorkerProcess(); /* is this autovacuum? */ + msg.m_adopt_counts = adopt_counts; + msg.m_autovacuum = IsAutoVacuumWorkerProcess(); msg.m_vacuumtime = GetCurrentTimestamp(); msg.m_tuples = tuples; pgstat_send(&msg, sizeof(msg)); @@ -1210,8 +1210,8 @@ pgstat_report_vacuum(Oid tableoid, bool shared, bool scanned_all, * -------- */ void -pgstat_report_analyze(Relation rel, PgStat_Counter livetuples, - PgStat_Counter deadtuples) +pgstat_report_analyze(Relation rel, bool adopt_counts, + PgStat_Counter livetuples, PgStat_Counter deadtuples) { PgStat_MsgAnalyze msg; @@ -1235,10 +1235,10 @@ pgstat_report_analyze(Relation rel, PgStat_Counter livetuples, for (trans = rel->pgstat_info->trans; trans; trans = trans->upper) { livetuples -= trans->tuples_inserted - trans->tuples_deleted; - deadtuples -= trans->tuples_deleted; + deadtuples -= trans->tuples_updated + trans->tuples_deleted; } /* count stuff inserted by already-aborted subxacts, too */ - deadtuples -= rel->pgstat_info->t_counts.t_new_dead_tuples; + deadtuples -= rel->pgstat_info->t_counts.t_delta_dead_tuples; /* Since ANALYZE's counts are estimates, we could have underflowed */ livetuples = Max(livetuples, 0); deadtuples = Max(deadtuples, 0); @@ -1247,7 +1247,8 @@ pgstat_report_analyze(Relation rel, PgStat_Counter livetuples, pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANALYZE); msg.m_databaseid = rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId; msg.m_tableoid = RelationGetRelid(rel); - msg.m_autovacuum = IsAutoVacuumWorkerProcess(); /* is this autovacuum? */ + msg.m_adopt_counts = adopt_counts; + msg.m_autovacuum = IsAutoVacuumWorkerProcess(); msg.m_analyzetime = GetCurrentTimestamp(); msg.m_live_tuples = livetuples; msg.m_dead_tuples = deadtuples; @@ -1559,12 +1560,9 @@ pgstat_count_heap_insert(Relation rel) if (pgstat_track_counts && pgstat_info != NULL) { + /* We have to log the effect at the proper transactional level */ int nest_level = GetCurrentTransactionNestLevel(); - /* t_tuples_inserted is nontransactional, so just advance it */ - pgstat_info->t_counts.t_tuples_inserted++; - - /* We have to log the transactional effect at the proper level */ if (pgstat_info->trans == NULL || pgstat_info->trans->nest_level != nest_level) add_tabstat_xact_level(pgstat_info, nest_level); @@ -1583,22 +1581,18 @@ pgstat_count_heap_update(Relation rel, bool hot) if (pgstat_track_counts && pgstat_info != NULL) { + /* We have to log the effect at the proper transactional level */ int nest_level = GetCurrentTransactionNestLevel(); - /* t_tuples_updated is nontransactional, so just advance it */ - pgstat_info->t_counts.t_tuples_updated++; - /* ditto for the hot_update counter */ - if (hot) - pgstat_info->t_counts.t_tuples_hot_updated++; - - /* We have to log the transactional effect at the proper level */ if (pgstat_info->trans == NULL || pgstat_info->trans->nest_level != nest_level) add_tabstat_xact_level(pgstat_info, nest_level); - /* An UPDATE both inserts a new tuple and deletes the old */ - pgstat_info->trans->tuples_inserted++; - pgstat_info->trans->tuples_deleted++; + pgstat_info->trans->tuples_updated++; + + /* t_tuples_hot_updated is nontransactional, so just advance it */ + if (hot) + pgstat_info->t_counts.t_tuples_hot_updated++; } } @@ -1612,12 +1606,9 @@ pgstat_count_heap_delete(Relation rel) if (pgstat_track_counts && pgstat_info != NULL) { + /* We have to log the effect at the proper transactional level */ int nest_level = GetCurrentTransactionNestLevel(); - /* t_tuples_deleted is nontransactional, so just advance it */ - pgstat_info->t_counts.t_tuples_deleted++; - - /* We have to log the transactional effect at the proper level */ if (pgstat_info->trans == NULL || pgstat_info->trans->nest_level != nest_level) add_tabstat_xact_level(pgstat_info, nest_level); @@ -1630,7 +1621,7 @@ pgstat_count_heap_delete(Relation rel) * pgstat_update_heap_dead_tuples - update dead-tuples count * * The semantics of this are that we are reporting the nontransactional - * recovery of "delta" dead tuples; so t_new_dead_tuples decreases + * recovery of "delta" dead tuples; so t_delta_dead_tuples decreases * rather than increasing, and the change goes straight into the per-table * counter, not into transactional state. */ @@ -1640,7 +1631,7 @@ pgstat_update_heap_dead_tuples(Relation rel, int delta) PgStat_TableStatus *pgstat_info = rel->pgstat_info; if (pgstat_track_counts && pgstat_info != NULL) - pgstat_info->t_counts.t_new_dead_tuples -= delta; + pgstat_info->t_counts.t_delta_dead_tuples -= delta; } @@ -1684,16 +1675,29 @@ AtEOXact_PgStat(bool isCommit) Assert(trans->upper == NULL); tabstat = trans->parent; Assert(tabstat->trans == trans); + /* count attempted actions regardless of commit/abort */ + tabstat->t_counts.t_tuples_inserted += trans->tuples_inserted; + tabstat->t_counts.t_tuples_updated += trans->tuples_updated; + tabstat->t_counts.t_tuples_deleted += trans->tuples_deleted; if (isCommit) { - tabstat->t_counts.t_new_live_tuples += + /* insert adds a live tuple, delete removes one */ + tabstat->t_counts.t_delta_live_tuples += trans->tuples_inserted - trans->tuples_deleted; - tabstat->t_counts.t_new_dead_tuples += trans->tuples_deleted; + /* update and delete each create a dead tuple */ + tabstat->t_counts.t_delta_dead_tuples += + trans->tuples_updated + trans->tuples_deleted; + /* insert, update, delete each count as one change event */ + tabstat->t_counts.t_changed_tuples += + trans->tuples_inserted + trans->tuples_updated + + trans->tuples_deleted; } else { /* inserted tuples are dead, deleted tuples are unaffected */ - tabstat->t_counts.t_new_dead_tuples += trans->tuples_inserted; + tabstat->t_counts.t_delta_dead_tuples += + trans->tuples_inserted + trans->tuples_updated; + /* an aborted xact generates no changed_tuple events */ } tabstat->trans = NULL; } @@ -1742,6 +1746,7 @@ AtEOSubXact_PgStat(bool isCommit, int nestDepth) if (trans->upper && trans->upper->nest_level == nestDepth - 1) { trans->upper->tuples_inserted += trans->tuples_inserted; + trans->upper->tuples_updated += trans->tuples_updated; trans->upper->tuples_deleted += trans->tuples_deleted; tabstat->trans = trans->upper; pfree(trans); @@ -1767,10 +1772,17 @@ AtEOSubXact_PgStat(bool isCommit, int nestDepth) else { /* - * On abort, inserted tuples are dead (and can be bounced out - * to the top-level tabstat), deleted tuples are unaffected + * On abort, update top-level tabstat counts, then forget + * the subtransaction */ - tabstat->t_counts.t_new_dead_tuples += trans->tuples_inserted; + + /* count attempted actions regardless of commit/abort */ + tabstat->t_counts.t_tuples_inserted += trans->tuples_inserted; + tabstat->t_counts.t_tuples_updated += trans->tuples_updated; + tabstat->t_counts.t_tuples_deleted += trans->tuples_deleted; + /* inserted tuples are dead, deleted tuples are unaffected */ + tabstat->t_counts.t_delta_dead_tuples += + trans->tuples_inserted + trans->tuples_updated; tabstat->trans = trans->upper; pfree(trans); } @@ -1810,6 +1822,7 @@ AtPrepare_PgStat(void) Assert(tabstat->trans == trans); record.tuples_inserted = trans->tuples_inserted; + record.tuples_updated = trans->tuples_updated; record.tuples_deleted = trans->tuples_deleted; record.t_id = tabstat->t_id; record.t_shared = tabstat->t_shared; @@ -1874,9 +1887,17 @@ pgstat_twophase_postcommit(TransactionId xid, uint16 info, /* Find or create a tabstat entry for the rel */ pgstat_info = get_tabstat_entry(rec->t_id, rec->t_shared); - pgstat_info->t_counts.t_new_live_tuples += + /* Same math as in AtEOXact_PgStat, commit case */ + pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted; + pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated; + pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted; + pgstat_info->t_counts.t_delta_live_tuples += rec->tuples_inserted - rec->tuples_deleted; - pgstat_info->t_counts.t_new_dead_tuples += rec->tuples_deleted; + pgstat_info->t_counts.t_delta_dead_tuples += + rec->tuples_updated + rec->tuples_deleted; + pgstat_info->t_counts.t_changed_tuples += + rec->tuples_inserted + rec->tuples_updated + + rec->tuples_deleted; } /* @@ -1895,8 +1916,12 @@ pgstat_twophase_postabort(TransactionId xid, uint16 info, /* Find or create a tabstat entry for the rel */ pgstat_info = get_tabstat_entry(rec->t_id, rec->t_shared); - /* inserted tuples are dead, deleted tuples are no-ops */ - pgstat_info->t_counts.t_new_dead_tuples += rec->tuples_inserted; + /* Same math as in AtEOXact_PgStat, abort case */ + pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted; + pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated; + pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted; + pgstat_info->t_counts.t_delta_dead_tuples += + rec->tuples_inserted + rec->tuples_updated; } @@ -3045,7 +3070,7 @@ pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create) result->tuples_hot_updated = 0; result->n_live_tuples = 0; result->n_dead_tuples = 0; - result->last_anl_tuples = 0; + result->changes_since_analyze = 0; result->blocks_fetched = 0; result->blocks_hit = 0; @@ -3634,7 +3659,6 @@ pgstat_recv_inquiry(PgStat_MsgInquiry *msg, int len) static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) { - PgStat_TableEntry *tabmsg = &(msg->m_entry[0]); PgStat_StatDBEntry *dbentry; PgStat_StatTabEntry *tabentry; int i; @@ -3653,8 +3677,10 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) */ for (i = 0; i < msg->m_nentries; i++) { + PgStat_TableEntry *tabmsg = &(msg->m_entry[i]); + tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables, - (void *) &(tabmsg[i].t_id), + (void *) &(tabmsg->t_id), HASH_ENTER, &found); if (!found) @@ -3663,18 +3689,18 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) * If it's a new table entry, initialize counters to the values we * just got. */ - tabentry->numscans = tabmsg[i].t_counts.t_numscans; - tabentry->tuples_returned = tabmsg[i].t_counts.t_tuples_returned; - tabentry->tuples_fetched = tabmsg[i].t_counts.t_tuples_fetched; - tabentry->tuples_inserted = tabmsg[i].t_counts.t_tuples_inserted; - tabentry->tuples_updated = tabmsg[i].t_counts.t_tuples_updated; - tabentry->tuples_deleted = tabmsg[i].t_counts.t_tuples_deleted; - 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->numscans = tabmsg->t_counts.t_numscans; + tabentry->tuples_returned = tabmsg->t_counts.t_tuples_returned; + tabentry->tuples_fetched = tabmsg->t_counts.t_tuples_fetched; + tabentry->tuples_inserted = tabmsg->t_counts.t_tuples_inserted; + tabentry->tuples_updated = tabmsg->t_counts.t_tuples_updated; + tabentry->tuples_deleted = tabmsg->t_counts.t_tuples_deleted; + tabentry->tuples_hot_updated = tabmsg->t_counts.t_tuples_hot_updated; + tabentry->n_live_tuples = tabmsg->t_counts.t_delta_live_tuples; + tabentry->n_dead_tuples = tabmsg->t_counts.t_delta_dead_tuples; + tabentry->changes_since_analyze = tabmsg->t_counts.t_changed_tuples; + tabentry->blocks_fetched = tabmsg->t_counts.t_blocks_fetched; + tabentry->blocks_hit = tabmsg->t_counts.t_blocks_hit; tabentry->vacuum_timestamp = 0; tabentry->autovac_vacuum_timestamp = 0; @@ -3686,20 +3712,21 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) /* * Otherwise add the values to the existing entry. */ - tabentry->numscans += tabmsg[i].t_counts.t_numscans; - tabentry->tuples_returned += tabmsg[i].t_counts.t_tuples_returned; - tabentry->tuples_fetched += tabmsg[i].t_counts.t_tuples_fetched; - tabentry->tuples_inserted += tabmsg[i].t_counts.t_tuples_inserted; - tabentry->tuples_updated += tabmsg[i].t_counts.t_tuples_updated; - tabentry->tuples_deleted += tabmsg[i].t_counts.t_tuples_deleted; - 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->blocks_fetched += tabmsg[i].t_counts.t_blocks_fetched; - tabentry->blocks_hit += tabmsg[i].t_counts.t_blocks_hit; + tabentry->numscans += tabmsg->t_counts.t_numscans; + tabentry->tuples_returned += tabmsg->t_counts.t_tuples_returned; + tabentry->tuples_fetched += tabmsg->t_counts.t_tuples_fetched; + tabentry->tuples_inserted += tabmsg->t_counts.t_tuples_inserted; + tabentry->tuples_updated += tabmsg->t_counts.t_tuples_updated; + tabentry->tuples_deleted += tabmsg->t_counts.t_tuples_deleted; + tabentry->tuples_hot_updated += tabmsg->t_counts.t_tuples_hot_updated; + tabentry->n_live_tuples += tabmsg->t_counts.t_delta_live_tuples; + tabentry->n_dead_tuples += tabmsg->t_counts.t_delta_dead_tuples; + tabentry->changes_since_analyze += tabmsg->t_counts.t_changed_tuples; + tabentry->blocks_fetched += tabmsg->t_counts.t_blocks_fetched; + tabentry->blocks_hit += tabmsg->t_counts.t_blocks_hit; } - /* Clamp n_live_tuples in case of negative new_live_tuples */ + /* Clamp n_live_tuples in case of negative delta_live_tuples */ tabentry->n_live_tuples = Max(tabentry->n_live_tuples, 0); /* Likewise for n_dead_tuples */ tabentry->n_dead_tuples = Max(tabentry->n_dead_tuples, 0); @@ -3707,13 +3734,13 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) /* * Add per-table stats to the per-database entry, too. */ - dbentry->n_tuples_returned += tabmsg[i].t_counts.t_tuples_returned; - dbentry->n_tuples_fetched += tabmsg[i].t_counts.t_tuples_fetched; - dbentry->n_tuples_inserted += tabmsg[i].t_counts.t_tuples_inserted; - dbentry->n_tuples_updated += tabmsg[i].t_counts.t_tuples_updated; - dbentry->n_tuples_deleted += tabmsg[i].t_counts.t_tuples_deleted; - dbentry->n_blocks_fetched += tabmsg[i].t_counts.t_blocks_fetched; - dbentry->n_blocks_hit += tabmsg[i].t_counts.t_blocks_hit; + dbentry->n_tuples_returned += tabmsg->t_counts.t_tuples_returned; + dbentry->n_tuples_fetched += tabmsg->t_counts.t_tuples_fetched; + dbentry->n_tuples_inserted += tabmsg->t_counts.t_tuples_inserted; + dbentry->n_tuples_updated += tabmsg->t_counts.t_tuples_updated; + 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; } } @@ -3879,36 +3906,15 @@ pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len) tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid, true); - if (msg->m_autovacuum) - tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime; - else - tabentry->vacuum_timestamp = msg->m_vacuumtime; - if (msg->m_scanned_all) + if (msg->m_adopt_counts) tabentry->n_live_tuples = msg->m_tuples; /* Resetting dead_tuples to 0 is an approximation ... */ tabentry->n_dead_tuples = 0; - if (msg->m_analyze) - { - if (msg->m_scanned_all) - tabentry->last_anl_tuples = msg->m_tuples; - else - { - /* last_anl_tuples must never exceed n_live_tuples+n_dead_tuples */ - tabentry->last_anl_tuples = Min(tabentry->last_anl_tuples, - tabentry->n_live_tuples); - } - if (msg->m_autovacuum) - tabentry->autovac_analyze_timestamp = msg->m_vacuumtime; - else - tabentry->analyze_timestamp = msg->m_vacuumtime; - } + if (msg->m_autovacuum) + tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime; else - { - /* last_anl_tuples must never exceed n_live_tuples+n_dead_tuples */ - tabentry->last_anl_tuples = Min(tabentry->last_anl_tuples, - tabentry->n_live_tuples); - } + tabentry->vacuum_timestamp = msg->m_vacuumtime; } /* ---------- @@ -3930,13 +3936,22 @@ pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len) tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid, true); + if (msg->m_adopt_counts) + { + tabentry->n_live_tuples = msg->m_live_tuples; + tabentry->n_dead_tuples = msg->m_dead_tuples; + } + + /* + * We reset changes_since_analyze to zero, forgetting any changes that + * occurred while the ANALYZE was in progress. + */ + tabentry->changes_since_analyze = 0; + if (msg->m_autovacuum) tabentry->autovac_analyze_timestamp = msg->m_analyzetime; else tabentry->analyze_timestamp = msg->m_analyzetime; - tabentry->n_live_tuples = msg->m_live_tuples; - tabentry->n_dead_tuples = msg->m_dead_tuples; - tabentry->last_anl_tuples = msg->m_live_tuples + msg->m_dead_tuples; } diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 7c4efb9f3b..c68693a329 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -5,7 +5,7 @@ * * Copyright (c) 2001-2009, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.84 2009/11/28 23:38:08 tgl Exp $ + * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.85 2009/12/30 20:32:14 tgl Exp $ * ---------- */ #ifndef PGSTAT_H @@ -68,9 +68,9 @@ typedef int64 PgStat_Counter; * fetched by heap_fetch under the control of simple indexscans for this index. * * tuples_inserted/updated/deleted/hot_updated count attempted actions, - * regardless of whether the transaction committed. new_live_tuples and - * new_dead_tuples are properly adjusted depending on commit or abort. - * Note that new_live_tuples and new_dead_tuples can be negative! + * regardless of whether the transaction committed. delta_live_tuples, + * delta_dead_tuples, and changed_tuples are set depending on commit or abort. + * Note that delta_live_tuples and delta_dead_tuples can be negative! * ---------- */ typedef struct PgStat_TableCounts @@ -85,8 +85,9 @@ typedef struct PgStat_TableCounts PgStat_Counter t_tuples_deleted; PgStat_Counter t_tuples_hot_updated; - PgStat_Counter t_new_live_tuples; - PgStat_Counter t_new_dead_tuples; + PgStat_Counter t_delta_live_tuples; + PgStat_Counter t_delta_dead_tuples; + PgStat_Counter t_changed_tuples; PgStat_Counter t_blocks_fetched; PgStat_Counter t_blocks_hit; @@ -102,14 +103,14 @@ typedef struct PgStat_TableCounts /* ---------- * PgStat_TableStatus Per-table status within a backend * - * Most of the event counters are nontransactional, ie, we count events + * Many of the event counters are nontransactional, ie, we count events * in committed and aborted transactions alike. For these, we just count - * directly in the PgStat_TableStatus. However, new_live_tuples and - * new_dead_tuples must be derived from tuple insertion and deletion counts + * directly in the PgStat_TableStatus. However, delta_live_tuples, + * delta_dead_tuples, and changed_tuples must be derived from event counts * with awareness of whether the transaction or subtransaction committed or * aborted. Hence, we also keep a stack of per-(sub)transaction status * records for every table modified in the current transaction. At commit - * or abort, we propagate tuples_inserted and tuples_deleted up to the + * or abort, we propagate tuples_inserted/updated/deleted up to the * parent subtransaction level, or out to the parent PgStat_TableStatus, * as appropriate. * ---------- @@ -129,6 +130,7 @@ typedef struct PgStat_TableStatus typedef struct PgStat_TableXactStatus { PgStat_Counter tuples_inserted; /* tuples inserted in (sub)xact */ + PgStat_Counter tuples_updated; /* tuples updated in (sub)xact */ PgStat_Counter tuples_deleted; /* tuples deleted in (sub)xact */ int nest_level; /* subtransaction nest level */ /* links to other structs for same relation: */ @@ -274,7 +276,7 @@ typedef struct PgStat_MsgAutovacStart /* ---------- * PgStat_MsgVacuum Sent by the backend or autovacuum daemon - * after VACUUM or VACUUM ANALYZE + * after VACUUM * ---------- */ typedef struct PgStat_MsgVacuum @@ -282,9 +284,8 @@ typedef struct PgStat_MsgVacuum PgStat_MsgHdr m_hdr; Oid m_databaseid; Oid m_tableoid; - bool m_analyze; + bool m_adopt_counts; bool m_autovacuum; - bool m_scanned_all; TimestampTz m_vacuumtime; PgStat_Counter m_tuples; } PgStat_MsgVacuum; @@ -300,6 +301,7 @@ typedef struct PgStat_MsgAnalyze PgStat_MsgHdr m_hdr; Oid m_databaseid; Oid m_tableoid; + bool m_adopt_counts; bool m_autovacuum; TimestampTz m_analyzetime; PgStat_Counter m_live_tuples; @@ -478,7 +480,7 @@ typedef struct PgStat_StatTabEntry PgStat_Counter n_live_tuples; PgStat_Counter n_dead_tuples; - PgStat_Counter last_anl_tuples; + PgStat_Counter changes_since_analyze; PgStat_Counter blocks_fetched; PgStat_Counter blocks_hit; @@ -635,11 +637,10 @@ extern void pgstat_clear_snapshot(void); extern void pgstat_reset_counters(void); extern void pgstat_report_autovac(Oid dboid); -extern void pgstat_report_vacuum(Oid tableoid, bool shared, bool scanned_all, - bool analyze, PgStat_Counter tuples); -extern void pgstat_report_analyze(Relation rel, - PgStat_Counter livetuples, - PgStat_Counter deadtuples); +extern void pgstat_report_vacuum(Oid tableoid, bool shared, bool adopt_counts, + PgStat_Counter tuples); +extern void pgstat_report_analyze(Relation rel, bool adopt_counts, + PgStat_Counter livetuples, PgStat_Counter deadtuples); extern void pgstat_initialize(void); extern void pgstat_bestart(void);