1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Set pg_class.reltuples for partitioned tables

When commit 0827e8af70 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
This commit is contained in:
Alvaro Herrera
2021-04-09 11:29:08 -04:00
parent 1798d8f8b6
commit 0e69f705cc
3 changed files with 59 additions and 39 deletions

View File

@ -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.
@ -2207,6 +2218,40 @@ truncate_check_activity(Relation rel)
CheckTableNotInUse(rel, "TRUNCATE");
}
/*
* 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