Skip to content

Commit 1fc5a57

Browse files
VACUUM ANALYZE: Always update pg_class.reltuples.
vacuumlazy.c sometimes fails to update pg_class entries for each index (to ensure that pg_class.reltuples is current), even though analyze.c assumed that that must have happened during VACUUM ANALYZE. There are at least a couple of reasons for this. For example, vacuumlazy.c could fail to update pg_class when the index AM indicated that its statistics are merely an estimate, per the contract for amvacuumcleanup() routines established by commit e573459 back in 2006. Stop assuming that pg_class must have been updated with accurate statistics within VACUUM ANALYZE -- update pg_class for indexes at the same time as the table relation in all cases. That way VACUUM ANALYZE will never fail to keep pg_class.reltuples reasonably accurate. The only downside of this approach (compared to the old approach) is that it might inaccurately set pg_class.reltuples for indexes whose heap relation ends up with the same inaccurate value anyway. This doesn't seem too bad. We already consistently called vac_update_relstats() (to update pg_class) for the heap/table relation twice during any VACUUM ANALYZE -- once in vacuumlazy.c, and once in analyze.c. We now make sure that we call vac_update_relstats() at least once (though often twice) for each index. This is follow up work to commit 9f3665f, which dealt with issues in btvacuumcleanup(). Technically this fixes an unrelated issue, though. btvacuumcleanup() no longer provides an accurate num_index_tuples value following commit 9f3665f (when there was no btbulkdelete() call during the VACUUM operation in question), but hashvacuumcleanup() has worked in the same way for many years now. Author: Peter Geoghegan <pg@bowt.ie> Reviewed-By: Masahiko Sawada <sawada.mshk@gmail.com> Discussion: https://postgr.es/m/CAH2-WzknxdComjhqo4SUxVFk_Q1171GJO2ZgHZ1Y6pion6u8rA@mail.gmail.com Backpatch: 13-, just like commit 9f3665f.
1 parent 9663d12 commit 1fc5a57

File tree

2 files changed

+32
-21
lines changed

2 files changed

+32
-21
lines changed

src/backend/access/heap/vacuumlazy.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1717,7 +1717,8 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
17171717
end_parallel_vacuum(indstats, lps, nindexes);
17181718

17191719
/* Update index statistics */
1720-
update_index_statistics(Irel, indstats, nindexes);
1720+
if (vacrelstats->useindex)
1721+
update_index_statistics(Irel, indstats, nindexes);
17211722

17221723
/* If no indexes, make log report that lazy_vacuum_heap would've made */
17231724
if (vacuumed_pages)

src/backend/commands/analyze.c

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -611,15 +611,24 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
611611
PROGRESS_ANALYZE_PHASE_FINALIZE_ANALYZE);
612612

613613
/*
614-
* Update pages/tuples stats in pg_class ... but not if we're doing
615-
* inherited stats.
614+
* Update pages/tuples stats in pg_class, and report ANALYZE to the stats
615+
* collector ... but not if we're doing inherited stats.
616+
*
617+
* We assume that VACUUM hasn't set pg_class.reltuples already, even
618+
* during a VACUUM ANALYZE. Although VACUUM often updates pg_class,
619+
* exceptions exists. A "VACUUM (ANALYZE, INDEX_CLEANUP OFF)" command
620+
* will never update pg_class entries for index relations. It's also
621+
* possible that an individual index's pg_class entry won't be updated
622+
* during VACUUM if the index AM returns NULL from its amvacuumcleanup()
623+
* routine.
616624
*/
617625
if (!inh)
618626
{
619627
BlockNumber relallvisible;
620628

621629
visibilitymap_count(onerel, &relallvisible, NULL);
622630

631+
/* Update pg_class for table relation */
623632
vac_update_relstats(onerel,
624633
relpages,
625634
totalrows,
@@ -628,15 +637,8 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
628637
InvalidTransactionId,
629638
InvalidMultiXactId,
630639
in_outer_xact);
631-
}
632640

633-
/*
634-
* Same for indexes. Vacuum always scans all indexes, so if we're part of
635-
* VACUUM ANALYZE, don't overwrite the accurate count already inserted by
636-
* VACUUM.
637-
*/
638-
if (!inh && !(params->options & VACOPT_VACUUM))
639-
{
641+
/* Same for indexes */
640642
for (ind = 0; ind < nindexes; ind++)
641643
{
642644
AnlIndexData *thisdata = &indexdata[ind];
@@ -652,20 +654,28 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
652654
InvalidMultiXactId,
653655
in_outer_xact);
654656
}
655-
}
656657

657-
/*
658-
* Report ANALYZE to the stats collector, too. However, if doing
659-
* inherited stats we shouldn't report, because the stats collector only
660-
* tracks per-table stats. Reset the changes_since_analyze counter only
661-
* if we analyzed all columns; otherwise, there is still work for
662-
* auto-analyze to do.
663-
*/
664-
if (!inh)
658+
/*
659+
* Now report ANALYZE to the stats collector.
660+
*
661+
* We deliberately don't report to the stats collector when doing
662+
* inherited stats, because the stats collector only tracks per-table
663+
* stats.
664+
*
665+
* Reset the changes_since_analyze counter only if we analyzed all
666+
* columns; otherwise, there is still work for auto-analyze to do.
667+
*/
665668
pgstat_report_analyze(onerel, totalrows, totaldeadrows,
666669
(va_cols == NIL));
670+
}
667671

668-
/* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup */
672+
/*
673+
* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup.
674+
*
675+
* Note that most index AMs perform a no-op as a matter of policy for
676+
* amvacuumcleanup() when called in ANALYZE-only mode. The only exception
677+
* among core index AMs is GIN/ginvacuumcleanup().
678+
*/
669679
if (!(params->options & VACOPT_VACUUM))
670680
{
671681
for (ind = 0; ind < nindexes; ind++)

0 commit comments

Comments
 (0)