aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2021-04-09 11:29:08 -0400
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2021-04-09 11:50:33 -0400
commit0e69f705cc1a3df273b38c9883fb5765991e04fe (patch)
tree31e8a0bb4305d1718ebff89d759fb87928399b89 /src
parent1798d8f8b6fbb8ff922f640ff2d5dbd3e47064a2 (diff)
downloadpostgresql-0e69f705cc1a3df273b38c9883fb5765991e04fe.tar.gz
postgresql-0e69f705cc1a3df273b38c9883fb5765991e04fe.zip
Set pg_class.reltuples for partitioned tables
When commit 0827e8af70f4 added auto-analyze support for partitioned tables, it included code to obtain reltuples for the partitioned table as a number of catalog accesses to read pg_class.reltuples for each partition. That's not only very inefficient, but also problematic because autovacuum doesn't hold any locks on any of those tables -- and doesn't want to. Replace that code with a read of pg_class.reltuples for the partitioned table, and make sure ANALYZE and TRUNCATE properly maintain that value. I found no code that would be affected by the change of relpages from zero to non-zero for partitioned tables, and no other code that should be maintaining it, but if there is, hopefully it'll be an easy fix. Per buildfarm. Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Zhihong Yu <zyu@yugabyte.com> Discussion: https://postgr.es/m/1823909.1617862590@sss.pgh.pa.us
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/analyze.c12
-rw-r--r--src/backend/commands/tablecmds.c47
-rw-r--r--src/backend/postmaster/autovacuum.c39
3 files changed, 59 insertions, 39 deletions
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 182a1330332..cffcd543029 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -656,6 +656,18 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
in_outer_xact);
}
}
+ else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * Partitioned tables don't have storage, so we don't set any fields in
+ * their pg_class entries except for relpages, which is necessary for
+ * auto-analyze to work properly.
+ */
+ vac_update_relstats(onerel, -1, totalrows,
+ 0, false, InvalidTransactionId,
+ InvalidMultiXactId,
+ in_outer_xact);
+ }
/*
* Now report ANALYZE to the stats collector. For regular tables, we do
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1f19629a949..f780918a951 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -337,6 +337,7 @@ typedef struct ForeignTruncateInfo
static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
static void truncate_check_activity(Relation rel);
+static void truncate_update_partedrel_stats(List *parted_rels);
static void RangeVarCallbackForTruncate(const RangeVar *relation,
Oid relId, Oid oldRelId, void *arg);
static List *MergeAttributes(List *schema, List *supers, char relpersistence,
@@ -1755,6 +1756,7 @@ ExecuteTruncateGuts(List *explicit_rels,
{
List *rels;
List *seq_relids = NIL;
+ List *parted_rels = NIL;
HTAB *ft_htab = NULL;
EState *estate;
ResultRelInfo *resultRelInfos;
@@ -1908,9 +1910,15 @@ ExecuteTruncateGuts(List *explicit_rels,
Relation rel = (Relation) lfirst(lc1);
int extra = lfirst_int(lc2);
- /* Skip partitioned tables as there is nothing to do */
+ /*
+ * Save OID of partitioned tables for later; nothing else to do for
+ * them here.
+ */
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ parted_rels = lappend_oid(parted_rels, RelationGetRelid(rel));
continue;
+ }
/*
* Build the lists of foreign tables belonging to each foreign server
@@ -2061,6 +2069,9 @@ ExecuteTruncateGuts(List *explicit_rels,
ResetSequence(seq_relid);
}
+ /* Reset partitioned tables' pg_class.reltuples */
+ truncate_update_partedrel_stats(parted_rels);
+
/*
* Write a WAL record to allow this set of actions to be logically
* decoded.
@@ -2208,6 +2219,40 @@ truncate_check_activity(Relation rel)
}
/*
+ * Update pg_class.reltuples for all the given partitioned tables to 0.
+ */
+static void
+truncate_update_partedrel_stats(List *parted_rels)
+{
+ Relation pg_class;
+ ListCell *lc;
+
+ pg_class = table_open(RelationRelationId, RowExclusiveLock);
+
+ foreach(lc, parted_rels)
+ {
+ Oid relid = lfirst_oid(lc);
+ HeapTuple tuple;
+ Form_pg_class rd_rel;
+
+ tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for relation %u", relid);
+ rd_rel = (Form_pg_class) GETSTRUCT(tuple);
+ if (rd_rel->reltuples != (float4) 0)
+ {
+ rd_rel->reltuples = (float4) 0;
+
+ heap_inplace_update(pg_class, tuple);
+ }
+
+ heap_freetuple(tuple);
+ }
+
+ table_close(pg_class, RowExclusiveLock);
+}
+
+/*
* storage_name
* returns the name corresponding to a typstorage/attstorage enum value
*/
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index aef9ac4dd22..a799544738e 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -3209,44 +3209,7 @@ relation_needs_vacanalyze(Oid relid,
*/
if (PointerIsValid(tabentry) && AutoVacuumingActive())
{
- if (classForm->relkind != RELKIND_PARTITIONED_TABLE)
- {
- reltuples = classForm->reltuples;
- }
- else
- {
- /*
- * If the relation is a partitioned table, we must add up
- * children's reltuples.
- */
- List *children;
- ListCell *lc;
-
- reltuples = 0;
-
- /* Find all members of inheritance set taking AccessShareLock */
- children = find_all_inheritors(relid, AccessShareLock, NULL);
-
- foreach(lc, children)
- {
- Oid childOID = lfirst_oid(lc);
- HeapTuple childtuple;
- Form_pg_class childclass;
-
- childtuple = SearchSysCache1(RELOID, ObjectIdGetDatum(childOID));
- childclass = (Form_pg_class) GETSTRUCT(childtuple);
-
- /* Skip a partitioned table and foreign partitions */
- if (RELKIND_HAS_STORAGE(childclass->relkind))
- {
- /* Sum up the child's reltuples for its parent table */
- reltuples += childclass->reltuples;
- }
- ReleaseSysCache(childtuple);
- }
-
- list_free(children);
- }
+ reltuples = classForm->reltuples;
vactuples = tabentry->n_dead_tuples;
instuples = tabentry->inserts_since_vacuum;
anltuples = tabentry->changes_since_analyze;