diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index 2713883..4881f18 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -373,6 +373,14 @@
The visibility map is vastly smaller than the heap, so it can easily be
cached even when the heap is very large.
+
+
+ Note that operations that rewrite the table, such as VACUUM
+ FULL, CLUSTER, and some versions of
+ ALTER TABLE also reset the visibility map.
+ It is recommended to always issue a standard VACUUM
+ after such commands to rebuild it.
+
@@ -476,8 +484,7 @@
autovacuum_freeze_max_age> minus
vacuum_freeze_min_age> transactions.
For tables that are regularly vacuumed for space reclamation purposes,
- this is of little importance. However, for static tables
- (including tables that receive inserts, but no updates or deletes),
+ this is of little importance. However, for static tables,
there is no need to vacuum for space reclamation, so it can
be useful to try to maximize the interval between forced autovacuums
on very large static tables. Obviously one can do this either by
@@ -739,7 +746,7 @@ HINT: Stop the postmaster and vacuum that database in single-user mode.
transactions old are always
vacuumed (this also applies to those tables whose freeze max age has
been modified via storage parameters; see below). Otherwise, if the
- number of tuples obsoleted since the last
+ number of tuples obsoleted or inserted since the last
VACUUM exceeds the vacuum threshold
, the
table is vacuumed. The vacuum threshold is defined as:
@@ -751,10 +758,11 @@ vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuple
,
and the number of tuples is
pg_class.reltuples.
- The number of obsolete tuples is obtained from the statistics
- collector; it is a semi-accurate count updated by each
- UPDATE and DELETE operation. (It
- is only semi-accurate because some information might be lost under heavy
+ The number of obsoleted and inserted tuples is obtained from the statistics
+ collector; they are semi-accurate counts updated by each
+ INSERT, UPDATE,
+ and DELETE operation. (They are
+ only semi-accurate because some information might be lost under heavy
load.) If the relfrozenxid> value of the table is more
than vacuum_freeze_table_age> transactions old, an aggressive
vacuum is performed to freeze old tuples and advance
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 0776428..646e0d8 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -1818,6 +1818,11 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
Estimated number of dead rows
+ n_ins_since_vacuum>
+ bigint>
+ Estimated number of rows inserted since this table was last vacuumed
+
+
n_mod_since_analyze>
bigint>
Estimated number of rows modified since this table was last analyzed
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index ada2142..3696faa 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -457,6 +457,7 @@ CREATE VIEW pg_stat_all_tables AS
pg_stat_get_tuples_hot_updated(C.oid) AS n_tup_hot_upd,
pg_stat_get_live_tuples(C.oid) AS n_live_tup,
pg_stat_get_dead_tuples(C.oid) AS n_dead_tup,
+ pg_stat_get_ins_since_vacuum(C.oid) AS n_ins_since_vacuum,
pg_stat_get_mod_since_analyze(C.oid) AS n_mod_since_analyze,
pg_stat_get_last_vacuum_time(C.oid) as last_vacuum,
pg_stat_get_last_autovacuum_time(C.oid) as last_autovacuum,
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 3768f50..7ebcc05 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2681,9 +2681,10 @@ relation_needs_vacanalyze(Oid relid,
float4 vacthresh,
anlthresh;
- /* number of vacuum (resp. analyze) tuples at this time */
+ /* number of vacuum/analyze/inserted tuples at this time */
float4 vactuples,
- anltuples;
+ anltuples,
+ instuples;
/* freeze parameters */
int freeze_max_age;
@@ -2764,6 +2765,7 @@ relation_needs_vacanalyze(Oid relid,
reltuples = classForm->reltuples;
vactuples = tabentry->n_dead_tuples;
anltuples = tabentry->changes_since_analyze;
+ instuples = tabentry->inserts_since_vacuum;
vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;
anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
@@ -2773,12 +2775,12 @@ relation_needs_vacanalyze(Oid relid,
* reset, because if that happens, the last vacuum and analyze counts
* will be reset too.
*/
- elog(DEBUG3, "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
+ elog(DEBUG3, "%s: vac/ins: %.0f/%.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
NameStr(classForm->relname),
- vactuples, vacthresh, anltuples, anlthresh);
+ vactuples, instuples, vacthresh, anltuples, anlthresh);
/* Determine if this table needs vacuum or analyze. */
- *dovacuum = force_vacuum || (vactuples > vacthresh);
+ *dovacuum = force_vacuum || (vactuples > vacthresh) || (instuples > vacthresh);
*doanalyze = (anltuples > anlthresh);
}
else
@@ -2792,7 +2794,7 @@ relation_needs_vacanalyze(Oid relid,
*doanalyze = false;
}
- /* ANALYZE refuses to work with pg_statistics */
+ /* ANALYZE refuses to work with pg_statistic */
if (relid == StatisticRelationId)
*doanalyze = false;
}
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 8fa9edb..169be3f 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -3855,6 +3855,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->inserts_since_vacuum = 0;
result->changes_since_analyze = 0;
result->blocks_fetched = 0;
result->blocks_hit = 0;
@@ -4966,6 +4967,7 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
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->inserts_since_vacuum = tabmsg->t_counts.t_tuples_inserted;
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;
@@ -4999,6 +5001,7 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
}
tabentry->n_live_tuples += tabmsg->t_counts.t_delta_live_tuples;
tabentry->n_dead_tuples += tabmsg->t_counts.t_delta_dead_tuples;
+ tabentry->inserts_since_vacuum += tabmsg->t_counts.t_tuples_inserted;
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;
@@ -5234,6 +5237,12 @@ pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
tabentry->n_live_tuples = msg->m_live_tuples;
tabentry->n_dead_tuples = msg->m_dead_tuples;
+ /*
+ * We reset inserts_since_vacuum to zero, forgetting any changes that
+ * occurred while the VACUUM was in progress.
+ */
+ tabentry->inserts_since_vacuum = 0;
+
if (msg->m_autovacuum)
{
tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime;
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 1bba5fa..982b11e 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -39,6 +39,7 @@ extern Datum pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_live_tuples(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_dead_tuples(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_ins_since_vacuum(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_blocks_hit(PG_FUNCTION_ARGS);
@@ -277,6 +278,22 @@ pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)
Datum
+pg_stat_get_ins_since_vacuum(PG_FUNCTION_ARGS)
+{
+ Oid relid = PG_GETARG_OID(0);
+ int64 result;
+ PgStat_StatTabEntry *tabentry;
+
+ if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
+ result = 0;
+ else
+ result = (int64) (tabentry->inserts_since_vacuum);
+
+ PG_RETURN_INT64(result);
+}
+
+
+Datum
pg_stat_get_mod_since_analyze(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 e2d08ba..3a999ce 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2739,6 +2739,8 @@ DATA(insert OID = 2878 ( pg_stat_get_live_tuples PGNSP PGUID 12 1 0 0 0 f f f f
DESCR("statistics: number of live tuples");
DATA(insert OID = 2879 ( pg_stat_get_dead_tuples PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_dead_tuples _null_ _null_ _null_ ));
DESCR("statistics: number of dead tuples");
+DATA(insert OID = 4032 ( pg_stat_get_ins_since_vacuum PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_ins_since_vacuum _null_ _null_ _null_ ));
+DESCR("statistics: number of tuples inserted since last vacuum");
DATA(insert OID = 3177 ( pg_stat_get_mod_since_analyze PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_mod_since_analyze _null_ _null_ _null_ ));
DESCR("statistics: number of tuples changed since last analyze");
DATA(insert OID = 1934 ( pg_stat_get_blocks_fetched PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_blocks_fetched _null_ _null_ _null_ ));
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index dc3320d..d491c71 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -628,6 +628,7 @@ typedef struct PgStat_StatTabEntry
PgStat_Counter n_live_tuples;
PgStat_Counter n_dead_tuples;
+ PgStat_Counter inserts_since_vacuum;
PgStat_Counter changes_since_analyze;
PgStat_Counter blocks_fetched;
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 00700f2..45a0b07 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1693,6 +1693,7 @@ pg_stat_all_tables| SELECT c.oid AS relid,
pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd,
pg_stat_get_live_tuples(c.oid) AS n_live_tup,
pg_stat_get_dead_tuples(c.oid) AS n_dead_tup,
+ pg_stat_get_ins_since_vacuum(c.oid) AS n_ins_since_vacuum,
pg_stat_get_mod_since_analyze(c.oid) AS n_mod_since_analyze,
pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum,
pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum,
@@ -1826,6 +1827,7 @@ pg_stat_sys_tables| SELECT pg_stat_all_tables.relid,
pg_stat_all_tables.n_tup_hot_upd,
pg_stat_all_tables.n_live_tup,
pg_stat_all_tables.n_dead_tup,
+ pg_stat_all_tables.n_ins_since_vacuum,
pg_stat_all_tables.n_mod_since_analyze,
pg_stat_all_tables.last_vacuum,
pg_stat_all_tables.last_autovacuum,
@@ -1869,6 +1871,7 @@ pg_stat_user_tables| SELECT pg_stat_all_tables.relid,
pg_stat_all_tables.n_tup_hot_upd,
pg_stat_all_tables.n_live_tup,
pg_stat_all_tables.n_dead_tup,
+ pg_stat_all_tables.n_ins_since_vacuum,
pg_stat_all_tables.n_mod_since_analyze,
pg_stat_all_tables.last_vacuum,
pg_stat_all_tables.last_autovacuum,