Re: [HACKERS] More stats about skipped vacuums
От | Kyotaro HORIGUCHI |
---|---|
Тема | Re: [HACKERS] More stats about skipped vacuums |
Дата | |
Msg-id | 20171030.205750.246076862.horiguchi.kyotaro@lab.ntt.co.jp обсуждение исходный текст |
Ответ на | Re: [HACKERS] More stats about skipped vacuums (Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>) |
Ответы |
Re: [HACKERS] More stats about skipped vacuums
(Michael Paquier <michael.paquier@gmail.com>)
|
Список | pgsql-hackers |
At Thu, 26 Oct 2017 15:06:30 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote in <20171026.150630.115694437.horiguchi.kyotaro@lab.ntt.co.jp> > At Fri, 20 Oct 2017 19:15:16 +0900, Masahiko Sawada <sawada.mshk@gmail.com> wrote in <CAD21AoAkaw-u0feAVN_VrKZA5tvzp7jT=mQCQP-SvMegKXHHaw@mail.gmail.com> > > > n_mod_since_analyze | 20000 > > > + vacuum_requred | true > > > + last_vacuum_oldest_xid | 8023 > > > + last_vacuum_left_to_truncate | 5123 > > > + last_vacuum_truncated | 387 > > > last_vacuum | 2017-10-10 17:21:54.380805+09 > > > last_autovacuum | 2017-10-10 17:21:54.380805+09 > > > + last_autovacuum_status | Killed by lock conflict > > > ... > > > autovacuum_count | 128 > > > + incomplete_autovacuum_count | 53 > > > > > > # The last one might be needless.. > > > > I'm not sure that the above informations will help for users or DBA > > but personally I sometimes want to have the number of index scans of > > the last autovacuum in the pg_stat_user_tables view. That value > > indicates how efficiently vacuums performed and would be a signal to > > increase the setting of autovacuum_work_mem for user. > > Btree and all existing index AMs (except brin) seem to visit the > all pages in every index scan so it would be valuable. Instead > the number of visited index pages during a table scan might be > usable. It is more relevant to performance than the number of > scans, on the other hand it is a bit difficult to get something > worth from the number in a moment. I'll show the number of scans > in the first cut. > > > > Where the "Killed by lock conflict" is one of the followings. > > > > > > - Completed > > > - Truncation skipped > > > - Partially truncated > > > - Skipped > > > - Killed by lock conflict > > > > > > This seems enough to find the cause of a table bloat. The same > > > discussion could be applied to analyze but it might be the > > > another issue. > > > > > > There may be a better way to indicate the vacuum soundness. Any > > > opinions and suggestions are welcome. > > > > > > I'm going to make a patch to do the 'formal' one for the time > > > being. Done with small modifications. In the attached patch pg_stat_all_tables has the following new columns. Documentations is not provided at this stage. ----- n_mod_since_analyze | 0 + vacuum_required | not requried last_vacuum | last_autovacuum | 2017-10-30 18:51:32.060551+09last_analyze | last_autoanalyze | 2017-10-30 18:48:33.414711+09 vacuum_count | 0 + last_vacuum_truncated | 0 + last_vacuum_untruncated | 0 + last_vacuum_index_scans | 0 + last_vacuum_oldest_xmin | 2134 + last_vacuum_status | agressive vacuum completed + autovacuum_fail_count | 0 autovacuum_count | 5 analyze_count | 0 autoanalyze_count | 1 ----- Where each column shows the following infomation. + vacuum_required | not requried VACUUM requirement status. Takes the following values. - partial Partial (or normal) will be performed by the next autovacuum. The word "partial" is taken from the commentfor vacuum_set_xid_limits. - aggressive Aggressive scan will be performed by the next autovacuum. - required Any type of autovacuum will be performed. The type of scan is unknown because the view failed to take therequired lock on the table. (AutoVacuumrequirement()) - not required Next autovacuum won't perform scan on this relation. - not required (lock not acquired) Autovacuum should be disabled and the distance to freeze-limit is not known because required lock is not available. - close to freeze-limit xid Shown while autovacuum is disabled. The table is in the manual vacuum window to avoid anti-wraparoundautovacuum. + last_vacuum_truncated | 0 The number of truncated pages in the last completed (auto)vacuum. + last_vacuum_untruncated | 0 The number of pages the last completed (auto)vacuum tried to truncate but could not for somereason. + last_vacuum_index_scans | 0 The number of index scans performed in the last completed (auto)vacuum. + last_vacuum_oldest_xmin | 2134 The oldest xmin used in the last completed (auto)vacuum. + last_vacuum_status | agressive vacuum completed The finish status of the last vacuum. Takes the following values. (pg_stat_get_last_vacuum_status()) - completed The last partial (auto)vacuum is completed. - vacuum full completed The last VACUUM FULL is completed. - aggressive vacuum completed The last aggressive (auto)vacuum is completed. - error while $progress The last vacuum stopped by error while $progress. The $progress one of the vacuum progressphases. - canceled while $progress The last vacuum was canceled while $progress This is caused by user cancellation of manual vacuum or killed by another backend who wants to acquire lock on the relation. - skipped - lock unavailable The last autovacuum on the relation was skipped because required lock was not available. - unvacuumable A past autovacuum tried vacuum on the relation but it is not vacuumable for reasons of ownership oraccessibility problem. (Such relations are not shown in pg_stat_all_tables..) + autovacuum_fail_count | 0 The number of successive failure of vacuum on the relation. Reset to zero by completed vacuum. ====== In the patch, vacrelstats if pointed from a static variable and cancel reporting is performed in PG_CATCH() section in vacuum(). Every unthrown error like lock acquisition failure is reported by explicit pgstat_report_vacuum() with the corresponding finish code. Vacuum requirement status is calculated in AutoVacuumRequirment() and returned as a string. Access share lock on the target relation is required but it returns only available values if the lock is not available. I decided to return incomplete (coarse grained) result than wait for a lock that isn't known to be relased in a short time for a perfect result. regards, -- Kyotaro Horiguchi NTT Open Source Software Center From 336748b61559bee66328a241394b365ebaacba6a Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp> Date: Fri, 27 Oct 2017 17:36:12 +0900 Subject: [PATCH] Add several vacuum information in pg_stat_*_tables. ---src/backend/catalog/system_views.sql | 7 ++src/backend/commands/cluster.c | 2 +-src/backend/commands/vacuum.c | 105 ++++++++++++++++++++++--src/backend/commands/vacuumlazy.c | 103 +++++++++++++++++++++---src/backend/postmaster/autovacuum.c | 115 ++++++++++++++++++++++++++src/backend/postmaster/pgstat.c | 80 +++++++++++++++---src/backend/utils/adt/pgstatfuncs.c | 152 ++++++++++++++++++++++++++++++++++-src/include/catalog/pg_proc.h | 14 ++++src/include/commands/vacuum.h | 4 +-src/include/pgstat.h | 38 ++++++++-src/include/postmaster/autovacuum.h | 1 +src/test/regress/expected/rules.out | 21 +++++12 files changed, 606 insertions(+), 36 deletions(-) diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index dc40cde..452bf5d 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -523,11 +523,18 @@ CREATE VIEW pg_stat_all_tables AS 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_mod_since_analyze(C.oid) AS n_mod_since_analyze, + pg_stat_get_vacuum_necessity(C.oid) AS vacuum_required, pg_stat_get_last_vacuum_time(C.oid) as last_vacuum, pg_stat_get_last_autovacuum_time(C.oid) as last_autovacuum, pg_stat_get_last_analyze_time(C.oid)as last_analyze, pg_stat_get_last_autoanalyze_time(C.oid) as last_autoanalyze, pg_stat_get_vacuum_count(C.oid) AS vacuum_count, + pg_stat_get_last_vacuum_truncated(C.oid) AS last_vacuum_truncated, + pg_stat_get_last_vacuum_untruncated(C.oid) AS last_vacuum_untruncated, + pg_stat_get_last_vacuum_index_scans(C.oid) AS last_vacuum_index_scans, + pg_stat_get_last_vacuum_oldest_xmin(C.oid) AS last_vacuum_oldest_xmin, + pg_stat_get_last_vacuum_status(C.oid) AS last_vacuum_status, + pg_stat_get_autovacuum_fail_count(C.oid) AS autovacuum_fail_count, pg_stat_get_autovacuum_count(C.oid)AS autovacuum_count, pg_stat_get_analyze_count(C.oid) AS analyze_count, pg_stat_get_autoanalyze_count(C.oid) AS autoanalyze_count diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 48f1e6e..403b76d 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -850,7 +850,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose, */ vacuum_set_xid_limits(OldHeap,0, 0, 0, 0, &OldestXmin, &FreezeXid, NULL, &MultiXactCutoff, - NULL); + NULL, NULL, NULL); /* * FreezeXid will become the table's new relfrozenxid, and that mustn'tgo diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index cbd6e9b..a0c5a12 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -35,6 +35,7 @@#include "catalog/pg_inherits_fn.h"#include "catalog/pg_namespace.h"#include "commands/cluster.h" +#include "commands/progress.h"#include "commands/vacuum.h"#include "miscadmin.h"#include "nodes/makefuncs.h" @@ -367,6 +368,9 @@ vacuum(int options, List *relations, VacuumParams *params, } PG_CATCH(); { + /* report the final status of this vacuum */ + lazy_vacuum_cancel_handler(); + in_vacuum = false; VacuumCostActive = false; PG_RE_THROW(); @@ -585,6 +589,10 @@ get_all_vacuum_rels(void) * Xmax. * - mxactFullScanLimit is a value against which a table's relminmxidvalue is * compared to produce a full-table vacuum, as with xidFullScanLimit. + * - aggressive is set if it is not NULL and set true if the table needs + * aggressive scan. + * - close_to_wrap_around_limit is set if it is not NULL and set true if it is + * in anti-anti-wraparound window. * * xidFullScanLimit and mxactFullScanLimit can be passed as NULL if caller is * notinterested. @@ -599,9 +607,11 @@ vacuum_set_xid_limits(Relation rel, TransactionId *freezeLimit, TransactionId *xidFullScanLimit, MultiXactId *multiXactCutoff, - MultiXactId *mxactFullScanLimit) + MultiXactId *mxactFullScanLimit, + bool *aggressive, bool *close_to_wrap_around_limit){ int freezemin; + int freezemax; int mxid_freezemin; int effective_multixact_freeze_max_age; TransactionId limit; @@ -701,11 +711,13 @@ vacuum_set_xid_limits(Relation rel, *multiXactCutoff = mxactLimit; - if (xidFullScanLimit != NULL) + if (xidFullScanLimit != NULL || aggressive != NULL) { int freezetable; + bool maybe_anti_wrapround = false; - Assert(mxactFullScanLimit != NULL); + /* these two output should be requested together */ + Assert(xidFullScanLimit == NULL || mxactFullScanLimit != NULL); /* * Determine the table freeze ageto use: as specified by the caller, @@ -717,7 +729,14 @@ vacuum_set_xid_limits(Relation rel, freezetable = freeze_table_age; if (freezetable <0) freezetable = vacuum_freeze_table_age; - freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95); + + freezemax = autovacuum_freeze_max_age * 0.95; + if (freezemax < freezetable) + { + /* We may be in anti-anti-warparound window */ + freezetable = freezemax; + maybe_anti_wrapround = true; + } Assert(freezetable >= 0); /* @@ -728,7 +747,8 @@ vacuum_set_xid_limits(Relation rel, if (!TransactionIdIsNormal(limit)) limit = FirstNormalTransactionId; - *xidFullScanLimit = limit; + if (xidFullScanLimit) + *xidFullScanLimit = limit; /* * Similar to the above, determine the table freeze age to use for @@ -741,10 +761,20 @@ vacuum_set_xid_limits(Relation rel, freezetable = multixact_freeze_table_age; if (freezetable< 0) freezetable = vacuum_multixact_freeze_table_age; - freezetable = Min(freezetable, - effective_multixact_freeze_max_age * 0.95); + + freezemax = effective_multixact_freeze_max_age * 0.95; + if (freezemax < freezetable) + { + /* We may be in anti-anti-warparound window */ + freezetable = freezemax; + maybe_anti_wrapround = true; + } Assert(freezetable >= 0); + /* We may be in anti-anti-warparound window */ + if (effective_multixact_freeze_max_age * 0.95 < freezetable) + maybe_anti_wrapround = true; + /* * Compute MultiXact limit causing a full-table vacuum, being careful * to generate a valid MultiXactvalue. @@ -753,11 +783,38 @@ vacuum_set_xid_limits(Relation rel, if (mxactLimit < FirstMultiXactId) mxactLimit= FirstMultiXactId; - *mxactFullScanLimit = mxactLimit; + if (mxactFullScanLimit) + *mxactFullScanLimit = mxactLimit; + + /* + * We request an aggressive scan if the table's frozen Xid is now + * older than or equal to the requested Xid full-table scan limit; or + * if the table's minimum MultiXactId is older than or equal to the + * requested mxid full-table scan limit. + */ + if (aggressive) + { + *aggressive = + TransactionIdPrecedesOrEquals(rel->rd_rel->relfrozenxid, + limit); + *aggressive |= + MultiXactIdPrecedesOrEquals(rel->rd_rel->relminmxid, + mxactLimit); + + /* set close_to_wrap_around_limit if requested */ + if (close_to_wrap_around_limit) + *close_to_wrap_around_limit = + (*aggressive && maybe_anti_wrapround); + } + else + { + Assert (!close_to_wrap_around_limit); + } } else { Assert(mxactFullScanLimit == NULL); + Assert(aggressive == NULL); }} @@ -1410,6 +1467,9 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) if (!onerel) { + pgstat_report_vacuum(relid, false, + 0, 0, 0, 0, 0, PGSTAT_VACUUM_SKIP_LOCK_FAILED, + InvalidTransactionId, 0, 0); PopActiveSnapshot(); CommitTransactionCommand(); return false; @@ -1441,6 +1501,12 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) (errmsg("skipping\"%s\" --- only table or database owner can vacuum it", RelationGetRelationName(onerel)))); relation_close(onerel, lmode); + + pgstat_report_vacuum(RelationGetRelid(onerel), + onerel->rd_rel->relisshared, + 0, 0, 0, 0, 0, PGSTAT_VACUUM_SKIP_NONTARGET, + InvalidTransactionId, 0, 0); + PopActiveSnapshot(); CommitTransactionCommand(); return false; @@ -1458,6 +1524,12 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) (errmsg("skipping\"%s\" --- cannot vacuum non-tables or special system tables", RelationGetRelationName(onerel)))); relation_close(onerel, lmode); + + pgstat_report_vacuum(RelationGetRelid(onerel), + onerel->rd_rel->relisshared, + 0, 0, 0, 0, 0, PGSTAT_VACUUM_SKIP_NONTARGET, + InvalidTransactionId, 0, 0); + PopActiveSnapshot(); CommitTransactionCommand(); return false; @@ -1473,6 +1545,12 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) if (RELATION_IS_OTHER_TEMP(onerel)) { relation_close(onerel, lmode); + + pgstat_report_vacuum(RelationGetRelid(onerel), + onerel->rd_rel->relisshared, + 0, 0, 0, 0, 0, PGSTAT_VACUUM_SKIP_NONTARGET, + InvalidTransactionId, 0, 0); + PopActiveSnapshot(); CommitTransactionCommand(); return false; @@ -1486,6 +1564,12 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) if (onerel->rd_rel->relkind== RELKIND_PARTITIONED_TABLE) { relation_close(onerel, lmode); + + pgstat_report_vacuum(RelationGetRelid(onerel), + onerel->rd_rel->relisshared, + 0, 0, 0, 0, 0, PGSTAT_VACUUM_SKIP_NONTARGET, + InvalidTransactionId, 0, 0); + PopActiveSnapshot(); CommitTransactionCommand(); /* It's OK to proceed with ANALYZE on this table*/ @@ -1531,6 +1615,8 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) */ if (options& VACOPT_FULL) { + bool isshared = onerel->rd_rel->relisshared; + /* close relation before vacuuming, but hold lock until commit */ relation_close(onerel, NoLock); onerel = NULL; @@ -1538,6 +1624,9 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) /* VACUUM FULLis now a variant of CLUSTER; see cluster.c */ cluster_rel(relid, InvalidOid, false, (options& VACOPT_VERBOSE) != 0); + pgstat_report_vacuum(relid, isshared, 0, 0, 0, 0, 0, + PGSTAT_VACUUM_FULL_FINISHED, + InvalidTransactionId, 0, 0); } else lazy_vacuum_rel(onerel, options, params, vac_strategy); diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 172d213..372d661 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -55,6 +55,7 @@#include "postmaster/autovacuum.h"#include "storage/bufmgr.h"#include "storage/freespace.h" +#include "storage/ipc.h"#include "storage/lmgr.h"#include "utils/lsyscache.h"#include "utils/memutils.h" @@ -105,6 +106,8 @@typedef struct LVRelStats{ + Oid reloid; /* oid of the target relation */ + bool shared; /* is shared relation? */ /* hasindex = true means two-pass strategy; false meansone-pass */ bool hasindex; /* Overall statistics about rel */ @@ -119,6 +122,7 @@ typedef struct LVRelStats double new_rel_tuples; /* new estimated total # of tuples */ double new_dead_tuples; /* new estimated total # of dead tuples */ BlockNumber pages_removed; + BlockNumber pages_not_removed; double tuples_deleted; BlockNumber nonempty_pages; /* actually, last nonemptypage + 1 */ /* List of TIDs of tuples we intend to delete */ @@ -138,6 +142,7 @@ static int elevel = -1;static TransactionId OldestXmin;static TransactionId FreezeLimit;static MultiXactIdMultiXactCutoff; +static LVRelStats *current_lvstats;static BufferAccessStrategy vac_strategy; @@ -216,6 +221,7 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, else elevel = DEBUG2; + current_lvstats = NULL; pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM, RelationGetRelid(onerel)); @@ -227,29 +233,30 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, params->multixact_freeze_min_age, params->multixact_freeze_table_age, &OldestXmin,&FreezeLimit, &xidFullScanLimit, - &MultiXactCutoff, &mxactFullScanLimit); + &MultiXactCutoff, &mxactFullScanLimit, + &aggressive, NULL); - /* - * We request an aggressive scan if the table's frozen Xid is now older - * than or equal to the requested Xid full-table scan limit; or if the - * table's minimum MultiXactId is older than or equal to the requested - * mxid full-table scan limit; or if DISABLE_PAGE_SKIPPING was specified. - */ - aggressive = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid, - xidFullScanLimit); - aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid, - mxactFullScanLimit); + /* force aggressive scan if DISABLE_PAGE_SKIPPING was specified */ if (options & VACOPT_DISABLE_PAGE_SKIPPING) aggressive = true; vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); + vacrelstats->reloid = RelationGetRelid(onerel); + vacrelstats->shared = onerel->rd_rel->relisshared; vacrelstats->old_rel_pages = onerel->rd_rel->relpages; vacrelstats->old_rel_tuples= onerel->rd_rel->reltuples; vacrelstats->num_index_scans = 0; vacrelstats->pages_removed= 0; + vacrelstats->pages_not_removed = 0; vacrelstats->lock_waiter_detected = false; + /* + * Register current vacrelstats so that final status can be reported on + * interrupts + */ + current_lvstats = vacrelstats; + /* Open all indexes of the relation */ vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel); vacrelstats->hasindex= (nindexes > 0); @@ -280,8 +287,15 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, * Optionally truncate the relation. */ if (should_attempt_truncation(vacrelstats)) + { lazy_truncate_heap(onerel, vacrelstats); + /* just paranoia */ + if (vacrelstats->rel_pages >= vacrelstats->nonempty_pages) + vacrelstats->pages_not_removed += + vacrelstats->rel_pages - vacrelstats->nonempty_pages; + } + /* Report that we are now doing final cleanup */ pgstat_progress_update_param(PROGRESS_VACUUM_PHASE, PROGRESS_VACUUM_PHASE_FINAL_CLEANUP); @@ -339,10 +353,22 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, if (new_live_tuples < 0) new_live_tuples = 0; /* just in case */ - pgstat_report_vacuum(RelationGetRelid(onerel), + /* vacuum successfully finished. nothing to do on exit */ + current_lvstats = NULL; + + pgstat_report_vacuum(vacrelstats->reloid, onerel->rd_rel->relisshared, new_live_tuples, - vacrelstats->new_dead_tuples); + vacrelstats->new_dead_tuples, + vacrelstats->pages_removed, + vacrelstats->pages_not_removed, + vacrelstats->num_index_scans, + OldestXmin, + aggressive ? + PGSTAT_VACUUM_AGGRESSIVE_FINISHED : + PGSTAT_VACUUM_FINISHED, + 0, 0); + pgstat_progress_end_command(); /* and log the action if appropriate */ @@ -2205,3 +2231,54 @@ heap_page_is_all_visible(Relation rel, Buffer buf, return all_visible;} + +/* + * lazy_vacuum_cancel_handler - report interrupted vacuum status + */ +void +lazy_vacuum_cancel_handler(void) +{ + LVRelStats *stats = current_lvstats; + LocalPgBackendStatus *local_beentry; + PgBackendStatus *beentry; + int phase; + int err; + + current_lvstats = NULL; + + /* we have nothing to report */ + if (!stats) + return; + + /* get vacuum progress stored in backend status */ + local_beentry = pgstat_fetch_stat_local_beentry(MyBackendId); + if (!local_beentry) + return; + + beentry = &local_beentry->backendStatus; + + Assert (beentry && beentry->st_progress_command == PROGRESS_COMMAND_VACUUM); + + phase = beentry->st_progress_param[PROGRESS_VACUUM_PHASE]; + + /* we can reach here both on interrupt and error */ + if (geterrcode() == ERRCODE_QUERY_CANCELED) + err = PGSTAT_VACUUM_CANCELED; + else + err = PGSTAT_VACUUM_ERROR; + + /* + * vacuum has been canceled, report stats numbers without normalization + * here. (But currently they are not used.) + */ + pgstat_report_vacuum(stats->reloid, + stats->shared, + stats->new_rel_tuples, + stats->new_dead_tuples, + stats->pages_removed, + stats->pages_not_removed, + stats->num_index_scans, + OldestXmin, + err, + phase, geterrcode()); +} diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index c04c0b5..6c32d0b 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -831,6 +831,121 @@ shutdown:}/* + * Returns status string of auto vacuum on the relation + */ +char * +AutoVacuumRequirement(Oid reloid) +{ + Relation classRel; + Relation rel; + TupleDesc pg_class_desc; + HeapTuple tuple; + Form_pg_class classForm; + AutoVacOpts *relopts; + PgStat_StatTabEntry *tabentry; + PgStat_StatDBEntry *shared; + PgStat_StatDBEntry *dbentry; + int effective_multixact_freeze_max_age; + bool dovacuum; + bool doanalyze; + bool wraparound; + bool aggressive; + bool xid_calculated = false; + bool in_anti_wa_window = false; + char *ret = "not requried"; + + /* Compute the multixact age for which freezing is urgent. */ + effective_multixact_freeze_max_age = MultiXactMemberFreezeThreshold(); + + /* Fetch the pgclass entry for this relation */ + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(reloid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", reloid); + classForm = (Form_pg_class) GETSTRUCT(tuple); + + /* extract relopts for autovacuum */ + classRel = heap_open(RelationRelationId, AccessShareLock); + pg_class_desc = RelationGetDescr(classRel); + relopts = extract_autovac_opts(tuple, pg_class_desc); + heap_close(classRel, AccessShareLock); + + /* Fetch the pgstat shared entry and entry for this database */ + shared = pgstat_fetch_stat_dbentry(InvalidOid); + dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId); + + /* Fetch the pgstat entry for this table */ + tabentry = get_pgstat_tabentry_relid(reloid, classForm->relisshared, + shared, dbentry); + + /* + * Check if the relation needs vacuum. This function is intended to + * suggest aggresive vacuum for the last 5% window in + * autovacuum_freeze_max_age so the variable wraparound is ignored + * here. See vacuum_set_xid_limits for details. + */ + relation_needs_vacanalyze(reloid, relopts, classForm, tabentry, + effective_multixact_freeze_max_age, + &dovacuum, &doanalyze, &wraparound); + ReleaseSysCache(tuple); + + /* get further information if needed */ + rel = NULL; + + /* don't get stuck with lock */ + if (ConditionalLockRelationOid(reloid, AccessShareLock)) + rel = try_relation_open(reloid, NoLock); + + if (rel) + { + TransactionId OldestXmin, FreezeLimit; + MultiXactId MultiXactCutoff; + + vacuum_set_xid_limits(rel, + vacuum_freeze_min_age, + vacuum_freeze_table_age, + vacuum_multixact_freeze_min_age, + vacuum_multixact_freeze_table_age, + &OldestXmin, &FreezeLimit, NULL, + &MultiXactCutoff, NULL, + &aggressive, &in_anti_wa_window); + + xid_calculated = true; + relation_close(rel, AccessShareLock); + } + + /* choose the proper message according to the calculation above */ + if (xid_calculated) + { + if (dovacuum) + { + /* we don't care anti-wraparound if autovacuum is on */ + if (aggressive) + ret = "aggressive"; + else + ret = "partial"; + } + else if (in_anti_wa_window) + ret = "close to freeze-limit xid"; + /* otherwise just "not requried" */ + } + else + { + /* + * failed to compute xid limits. show less-grained messages. We can + * use just "required" in the autovacuum case is enough to distinguish + * from full-grained messages, but we require additional words in the + * case where autovacuum is turned off. + */ + if (dovacuum) + ret = "required"; + else + ret = "not required (lock not acquired)"; + } + + return ret; +} + +/* * Determine the time to sleep, based on the database list. * * The "canlaunch" parameter indicates whether we can starta worker right now, diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 3a0b49c..721b172 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -1403,7 +1403,13 @@ pgstat_report_autovac(Oid dboid) */voidpgstat_report_vacuum(Oid tableoid, bool shared, - PgStat_Counter livetuples, PgStat_Counter deadtuples) + PgStat_Counter livetuples, PgStat_Counter deadtuples, + PgStat_Counter pages_removed, + PgStat_Counter pages_not_removed, + PgStat_Counter num_index_scans, + TransactionId oldestxmin, + PgStat_Counter status, PgStat_Counter last_phase, + PgStat_Counter errcode){ PgStat_MsgVacuum msg; @@ -1417,6 +1423,13 @@ pgstat_report_vacuum(Oid tableoid, bool shared, msg.m_vacuumtime = GetCurrentTimestamp(); msg.m_live_tuples= livetuples; msg.m_dead_tuples = deadtuples; + msg.m_pages_removed = pages_removed; + msg.m_pages_not_removed = pages_not_removed; + msg.m_num_index_scans = num_index_scans; + msg.m_oldest_xmin = oldestxmin; + msg.m_vacuum_status = status; + msg.m_vacuum_last_phase = last_phase; + msg.m_vacuum_errcode = errcode; pgstat_send(&msg, sizeof(msg));} @@ -4576,17 +4589,25 @@ pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create) 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->changes_since_analyze = 0; + result->n_pages_removed = 0; + result->n_pages_not_removed = 0; + result->n_index_scans = 0; + result->oldest_xmin = InvalidTransactionId; + result->blocks_fetched = 0; result->blocks_hit = 0; + result->vacuum_timestamp = 0; result->vacuum_count = 0; result->autovac_vacuum_timestamp = 0; @@ -4595,6 +4616,11 @@ pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create) result->analyze_count= 0; result->autovac_analyze_timestamp = 0; result->autovac_analyze_count = 0; + + result->vacuum_status = 0; + result->vacuum_last_phase = 0; + result->vacuum_errcode = 0; + result->vacuum_failcount = 0; } return result; @@ -5979,18 +6005,50 @@ pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len) tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid,true); - tabentry->n_live_tuples = msg->m_live_tuples; - tabentry->n_dead_tuples = msg->m_dead_tuples; + tabentry->vacuum_status = msg->m_vacuum_status; + tabentry->vacuum_last_phase = msg->m_vacuum_last_phase; + tabentry->vacuum_errcode = msg->m_vacuum_errcode; - if (msg->m_autovacuum) - { - tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime; - tabentry->autovac_vacuum_count++; - } - else + /* + * We store the numbers only when the vacuum has been completed. They + * might be usable to find how much the stopped vacuum processed but we + * choose not to show them rather than show bogus numbers. + */ + switch ((StatVacuumStatus)msg->m_vacuum_status) { - tabentry->vacuum_timestamp = msg->m_vacuumtime; - tabentry->vacuum_count++; + case PGSTAT_VACUUM_FINISHED: + case PGSTAT_VACUUM_FULL_FINISHED: + case PGSTAT_VACUUM_AGGRESSIVE_FINISHED: + tabentry->n_live_tuples = msg->m_live_tuples; + tabentry->n_dead_tuples = msg->m_dead_tuples; + tabentry->n_pages_removed = msg->m_pages_removed; + tabentry->n_pages_not_removed = msg->m_pages_not_removed; + tabentry->n_index_scans = msg->m_num_index_scans; + tabentry->oldest_xmin = msg->m_oldest_xmin; + tabentry->vacuum_failcount = 0; + + if (msg->m_autovacuum) + { + tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime; + tabentry->autovac_vacuum_count++; + } + else + { + tabentry->vacuum_timestamp = msg->m_vacuumtime; + tabentry->vacuum_count++; + } + break; + + case PGSTAT_VACUUM_ERROR: + case PGSTAT_VACUUM_CANCELED: + case PGSTAT_VACUUM_SKIP_LOCK_FAILED: + tabentry->vacuum_failcount++; + break; + + case PGSTAT_VACUUM_SKIP_NONTARGET: + default: + /* don't increment failure count for non-target tables */ + break; }} diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 8d9e7c1..bddc243 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -23,6 +23,7 @@#include "pgstat.h"#include "postmaster/bgworker_internals.h"#include "postmaster/postmaster.h" +#include "postmaster/autovacuum.h"#include "storage/proc.h"#include "storage/procarray.h"#include "utils/acl.h" @@ -194,6 +195,156 @@ pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS) PG_RETURN_INT64(result);} +Datum +pg_stat_get_vacuum_necessity(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + PG_RETURN_TEXT_P(cstring_to_text(AutoVacuumRequirement(relid))); +} + +Datum +pg_stat_get_last_vacuum_truncated(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->n_pages_removed); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_last_vacuum_untruncated(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->n_pages_not_removed); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_last_vacuum_index_scans(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int32 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int32) (tabentry->n_index_scans); + + PG_RETURN_INT32(result); +} + +Datum +pg_stat_get_last_vacuum_oldest_xmin(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + TransactionId result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = InvalidTransactionId; + else + result = (int32) (tabentry->oldest_xmin); + + return TransactionIdGetDatum(result); +} + +Datum +pg_stat_get_last_vacuum_status(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + char *result = "unknown"; + PgStat_StatTabEntry *tabentry; + + /* + * status string. this must be synced with the strings shown by the + * statistics view "pg_stat_progress_vacuum" + */ + static char *phasestr[] = + {"initialization", + "scanning heap", + "vacuuming indexes", + "vacuuming heap", + "cleaning up indexes", + "trucating heap", + "performing final cleanup"}; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) != NULL) + { + int phase; + StatVacuumStatus status; + + status = tabentry->vacuum_status; + switch (status) + { + case PGSTAT_VACUUM_FINISHED: + result = "completed"; + break; + case PGSTAT_VACUUM_ERROR: + case PGSTAT_VACUUM_CANCELED: + phase = tabentry->vacuum_last_phase; + /* number of elements of phasestr above */ + if (phase >= 0 && phase <= 7) + result = psprintf("%s while %s", + status == PGSTAT_VACUUM_CANCELED ? + "canceled" : "error", + phasestr[phase]); + else + result = psprintf("unknown vacuum phase: %d", phase); + break; + case PGSTAT_VACUUM_SKIP_LOCK_FAILED: + result = "skipped - lock unavailable"; + break; + + case PGSTAT_VACUUM_AGGRESSIVE_FINISHED: + result = "aggressive vacuum completed"; + break; + + case PGSTAT_VACUUM_FULL_FINISHED: + result = "vacuum full completed"; + break; + + case PGSTAT_VACUUM_SKIP_NONTARGET: + result = "unvacuumable"; + break; + + default: + result = "unknown status"; + break; + } + } + + PG_RETURN_TEXT_P(cstring_to_text(result)); +} + +Datum +pg_stat_get_autovacuum_fail_count(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 = (int32) (tabentry->vacuum_failcount); + + PG_RETURN_INT32(result); +}Datumpg_stat_get_blocks_fetched(PG_FUNCTION_ARGS) @@ -210,7 +361,6 @@ pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS) PG_RETURN_INT64(result);} -Datumpg_stat_get_blocks_hit(PG_FUNCTION_ARGS){ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 93c031a..5a1c77d 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -2887,6 +2887,20 @@ DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f fDESCR("statistics:information about WAL receiver");DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 121 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}"_null_ _null_pg_stat_get_subscription _null_ _null_ _null_ ));DESCR("statistics: information about subscription"); +DATA(insert OID = 3419 ( pg_stat_get_vacuum_necessity PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 25 "26" _null_ _null__null_ _null_ _null_ pg_stat_get_vacuum_necessity _null_ _null_ _null_ )); +DESCR("statistics: true if needs vacuum"); +DATA(insert OID = 3420 ( pg_stat_get_last_vacuum_untruncated 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_last_vacuum_untruncated _null_ _null_ _null_ )); +DESCR("statistics: pages left untruncated in the last vacuum"); +DATA(insert OID = 3421 ( pg_stat_get_last_vacuum_truncated 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_last_vacuum_truncated _null_ _null_ _null_ )); +DESCR("statistics: pages truncated in the last vacuum"); +DATA(insert OID = 3422 ( pg_stat_get_last_vacuum_index_scans PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 23 "26" _null__null_ _null_ _null_ _null_ pg_stat_get_last_vacuum_index_scans _null_ _null_ _null_ )); +DESCR("statistics: number of index scans in the last vacuum"); +DATA(insert OID = 3423 ( pg_stat_get_last_vacuum_oldest_xmin PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 28 "26" _null__null_ _null_ _null_ _null_ pg_stat_get_last_vacuum_oldest_xmin _null_ _null_ _null_ )); +DESCR("statistics: The oldest xmin used in the last vacuum"); +DATA(insert OID = 3424 ( pg_stat_get_last_vacuum_status PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 25 "26" _null_ _null__null_ _null_ _null_ pg_stat_get_last_vacuum_status _null_ _null_ _null_ )); +DESCR("statistics: ending status of the last vacuum"); +DATA(insert OID = 3425 ( pg_stat_get_autovacuum_fail_count PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 23 "26" _null__null_ _null_ _null_ _null_ pg_stat_get_autovacuum_fail_count _null_ _null_ _null_ )); +DESCR("statistics: number of successively failed vacuum trials");DATA(insert OID = 2026 ( pg_backend_pid PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_));DESCR("statistics: current backend PID");DATA(insert OID = 1937 ( pg_stat_get_backend_pid PGNSP PGUID 121 0 0 0 f f f f t f s r 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_pid _null_ _null_ _null_ )); diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 7a7b793..6091bab 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -182,13 +182,15 @@ extern void vacuum_set_xid_limits(Relation rel, TransactionId *freezeLimit, TransactionId *xidFullScanLimit, MultiXactId *multiXactCutoff, - MultiXactId *mxactFullScanLimit); + MultiXactId *mxactFullScanLimit, + bool *aggressive, bool *in_wa_window);extern void vac_update_datfrozenxid(void);extern void vacuum_delay_point(void);/*in commands/vacuumlazy.c */extern void lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, BufferAccessStrategy bstrategy); +extern void lazy_vacuum_cancel_handler(void);/* in commands/analyze.c */extern void analyze_rel(Oid relid, RangeVar *relation,int options, diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 089b7c3..bab8332 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -67,6 +67,20 @@ typedef enum StatMsgType PGSTAT_MTYPE_DEADLOCK} StatMsgType; +/* + * The exit status stored in vacuum report. + */ +typedef enum StatVacuumStatus +{ + PGSTAT_VACUUM_FINISHED, + PGSTAT_VACUUM_CANCELED, + PGSTAT_VACUUM_ERROR, + PGSTAT_VACUUM_SKIP_LOCK_FAILED, + PGSTAT_VACUUM_SKIP_NONTARGET, + PGSTAT_VACUUM_AGGRESSIVE_FINISHED, + PGSTAT_VACUUM_FULL_FINISHED +} StatVacuumStatus; +/* ---------- * The data type used for counters. * ---------- @@ -369,6 +383,13 @@ typedef struct PgStat_MsgVacuum TimestampTz m_vacuumtime; PgStat_Counter m_live_tuples; PgStat_Counterm_dead_tuples; + PgStat_Counter m_pages_removed; + PgStat_Counter m_pages_not_removed; + PgStat_Counter m_num_index_scans; + TransactionId m_oldest_xmin; + PgStat_Counter m_vacuum_status; + PgStat_Counter m_vacuum_last_phase; + PgStat_Counter m_vacuum_errcode;} PgStat_MsgVacuum; @@ -629,6 +650,10 @@ typedef struct PgStat_StatTabEntry PgStat_Counter n_live_tuples; PgStat_Counter n_dead_tuples; PgStat_Counter changes_since_analyze; + PgStat_Counter n_pages_removed; + PgStat_Counter n_pages_not_removed; + PgStat_Counter n_index_scans; + TransactionId oldest_xmin; PgStat_Counter blocks_fetched; PgStat_Counter blocks_hit; @@ -641,6 +666,11 @@ typedef struct PgStat_StatTabEntry PgStat_Counter analyze_count; TimestampTz autovac_analyze_timestamp; /* autovacuum initiated */ PgStat_Counter autovac_analyze_count; + + PgStat_Counter vacuum_status; + PgStat_Counter vacuum_last_phase; + PgStat_Counter vacuum_errcode; + PgStat_Counter vacuum_failcount;} PgStat_StatTabEntry; @@ -1165,7 +1195,13 @@ extern void pgstat_reset_single_counter(Oid objectid, PgStat_Single_Reset_Type textern void pgstat_report_autovac(Oiddboid);extern void pgstat_report_vacuum(Oid tableoid, bool shared, - PgStat_Counter livetuples, PgStat_Counter deadtuples); + PgStat_Counter livetuples, PgStat_Counter deadtuples, + PgStat_Counter pages_removed, + PgStat_Counter pages_not_removed, + PgStat_Counter num_index_scans, + TransactionId oldextxmin, + PgStat_Counter status, PgStat_Counter last_phase, + PgStat_Counter errcode);extern void pgstat_report_analyze(Relation rel, PgStat_Counterlivetuples, PgStat_Counter deadtuples, bool resetcounter); diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index 3469915..848a322 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -49,6 +49,7 @@ extern int Log_autovacuum_min_duration;extern bool AutoVacuumingActive(void);extern bool IsAutoVacuumLauncherProcess(void);externbool IsAutoVacuumWorkerProcess(void); +extern char *AutoVacuumRequirement(Oid reloid);#define IsAnyAutoVacuumProcess() \ (IsAutoVacuumLauncherProcess() || IsAutoVacuumWorkerProcess()) diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index f1c1b44..fb1ea49 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1759,11 +1759,18 @@ pg_stat_all_tables| SELECT c.oid AS relid, 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_mod_since_analyze(c.oid) AS n_mod_since_analyze, + pg_stat_get_vacuum_necessity(c.oid) AS vacuum_required, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid)AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid)AS last_autoanalyze, pg_stat_get_vacuum_count(c.oid) AS vacuum_count, + pg_stat_get_last_vacuum_truncated(c.oid) AS last_vacuum_truncated, + pg_stat_get_last_vacuum_untruncated(c.oid) AS last_vacuum_untruncated, + pg_stat_get_last_vacuum_index_scans(c.oid) AS last_vacuum_index_scans, + pg_stat_get_last_vacuum_oldest_xmin(c.oid) AS last_vacuum_oldest_xmin, + pg_stat_get_last_vacuum_status(c.oid) AS last_vacuum_status, + pg_stat_get_autovacuum_fail_count(c.oid) AS autovacuum_fail_count, pg_stat_get_autovacuum_count(c.oid) AS autovacuum_count, pg_stat_get_analyze_count(c.oid) AS analyze_count, pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count @@ -1906,11 +1913,18 @@ pg_stat_sys_tables| SELECT pg_stat_all_tables.relid, pg_stat_all_tables.n_live_tup, pg_stat_all_tables.n_dead_tup, pg_stat_all_tables.n_mod_since_analyze, + pg_stat_all_tables.vacuum_required, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze, pg_stat_all_tables.vacuum_count, + pg_stat_all_tables.last_vacuum_truncated, + pg_stat_all_tables.last_vacuum_untruncated, + pg_stat_all_tables.last_vacuum_index_scans, + pg_stat_all_tables.last_vacuum_oldest_xmin, + pg_stat_all_tables.last_vacuum_status, + pg_stat_all_tables.autovacuum_fail_count, pg_stat_all_tables.autovacuum_count, pg_stat_all_tables.analyze_count, pg_stat_all_tables.autoanalyze_count @@ -1949,11 +1963,18 @@ pg_stat_user_tables| SELECT pg_stat_all_tables.relid, pg_stat_all_tables.n_live_tup, pg_stat_all_tables.n_dead_tup, pg_stat_all_tables.n_mod_since_analyze, + pg_stat_all_tables.vacuum_required, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze, pg_stat_all_tables.vacuum_count, + pg_stat_all_tables.last_vacuum_truncated, + pg_stat_all_tables.last_vacuum_untruncated, + pg_stat_all_tables.last_vacuum_index_scans, + pg_stat_all_tables.last_vacuum_oldest_xmin, + pg_stat_all_tables.last_vacuum_status, + pg_stat_all_tables.autovacuum_fail_count, pg_stat_all_tables.autovacuum_count, pg_stat_all_tables.analyze_count, pg_stat_all_tables.autoanalyze_count -- 2.9.2 -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
В списке pgsql-hackers по дате отправления: