Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0e69f70

Browse files
committed
Set pg_class.reltuples for partitioned tables
When commit 0827e8a 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
1 parent 1798d8f commit 0e69f70

File tree

3 files changed

+59
-39
lines changed

3 files changed

+59
-39
lines changed

src/backend/commands/analyze.c

+12
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,18 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
656656
in_outer_xact);
657657
}
658658
}
659+
else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
660+
{
661+
/*
662+
* Partitioned tables don't have storage, so we don't set any fields in
663+
* their pg_class entries except for relpages, which is necessary for
664+
* auto-analyze to work properly.
665+
*/
666+
vac_update_relstats(onerel, -1, totalrows,
667+
0, false, InvalidTransactionId,
668+
InvalidMultiXactId,
669+
in_outer_xact);
670+
}
659671

660672
/*
661673
* Now report ANALYZE to the stats collector. For regular tables, we do

src/backend/commands/tablecmds.c

+46-1
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ typedef struct ForeignTruncateInfo
337337
static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
338338
static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
339339
static void truncate_check_activity(Relation rel);
340+
static void truncate_update_partedrel_stats(List *parted_rels);
340341
static void RangeVarCallbackForTruncate(const RangeVar *relation,
341342
Oid relId, Oid oldRelId, void *arg);
342343
static List *MergeAttributes(List *schema, List *supers, char relpersistence,
@@ -1755,6 +1756,7 @@ ExecuteTruncateGuts(List *explicit_rels,
17551756
{
17561757
List *rels;
17571758
List *seq_relids = NIL;
1759+
List *parted_rels = NIL;
17581760
HTAB *ft_htab = NULL;
17591761
EState *estate;
17601762
ResultRelInfo *resultRelInfos;
@@ -1908,9 +1910,15 @@ ExecuteTruncateGuts(List *explicit_rels,
19081910
Relation rel = (Relation) lfirst(lc1);
19091911
int extra = lfirst_int(lc2);
19101912

1911-
/* Skip partitioned tables as there is nothing to do */
1913+
/*
1914+
* Save OID of partitioned tables for later; nothing else to do for
1915+
* them here.
1916+
*/
19121917
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1918+
{
1919+
parted_rels = lappend_oid(parted_rels, RelationGetRelid(rel));
19131920
continue;
1921+
}
19141922

19151923
/*
19161924
* Build the lists of foreign tables belonging to each foreign server
@@ -2061,6 +2069,9 @@ ExecuteTruncateGuts(List *explicit_rels,
20612069
ResetSequence(seq_relid);
20622070
}
20632071

2072+
/* Reset partitioned tables' pg_class.reltuples */
2073+
truncate_update_partedrel_stats(parted_rels);
2074+
20642075
/*
20652076
* Write a WAL record to allow this set of actions to be logically
20662077
* decoded.
@@ -2207,6 +2218,40 @@ truncate_check_activity(Relation rel)
22072218
CheckTableNotInUse(rel, "TRUNCATE");
22082219
}
22092220

2221+
/*
2222+
* Update pg_class.reltuples for all the given partitioned tables to 0.
2223+
*/
2224+
static void
2225+
truncate_update_partedrel_stats(List *parted_rels)
2226+
{
2227+
Relation pg_class;
2228+
ListCell *lc;
2229+
2230+
pg_class = table_open(RelationRelationId, RowExclusiveLock);
2231+
2232+
foreach(lc, parted_rels)
2233+
{
2234+
Oid relid = lfirst_oid(lc);
2235+
HeapTuple tuple;
2236+
Form_pg_class rd_rel;
2237+
2238+
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
2239+
if (!HeapTupleIsValid(tuple))
2240+
elog(ERROR, "could not find tuple for relation %u", relid);
2241+
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
2242+
if (rd_rel->reltuples != (float4) 0)
2243+
{
2244+
rd_rel->reltuples = (float4) 0;
2245+
2246+
heap_inplace_update(pg_class, tuple);
2247+
}
2248+
2249+
heap_freetuple(tuple);
2250+
}
2251+
2252+
table_close(pg_class, RowExclusiveLock);
2253+
}
2254+
22102255
/*
22112256
* storage_name
22122257
* returns the name corresponding to a typstorage/attstorage enum value

src/backend/postmaster/autovacuum.c

+1-38
Original file line numberDiff line numberDiff line change
@@ -3209,44 +3209,7 @@ relation_needs_vacanalyze(Oid relid,
32093209
*/
32103210
if (PointerIsValid(tabentry) && AutoVacuumingActive())
32113211
{
3212-
if (classForm->relkind != RELKIND_PARTITIONED_TABLE)
3213-
{
3214-
reltuples = classForm->reltuples;
3215-
}
3216-
else
3217-
{
3218-
/*
3219-
* If the relation is a partitioned table, we must add up
3220-
* children's reltuples.
3221-
*/
3222-
List *children;
3223-
ListCell *lc;
3224-
3225-
reltuples = 0;
3226-
3227-
/* Find all members of inheritance set taking AccessShareLock */
3228-
children = find_all_inheritors(relid, AccessShareLock, NULL);
3229-
3230-
foreach(lc, children)
3231-
{
3232-
Oid childOID = lfirst_oid(lc);
3233-
HeapTuple childtuple;
3234-
Form_pg_class childclass;
3235-
3236-
childtuple = SearchSysCache1(RELOID, ObjectIdGetDatum(childOID));
3237-
childclass = (Form_pg_class) GETSTRUCT(childtuple);
3238-
3239-
/* Skip a partitioned table and foreign partitions */
3240-
if (RELKIND_HAS_STORAGE(childclass->relkind))
3241-
{
3242-
/* Sum up the child's reltuples for its parent table */
3243-
reltuples += childclass->reltuples;
3244-
}
3245-
ReleaseSysCache(childtuple);
3246-
}
3247-
3248-
list_free(children);
3249-
}
3212+
reltuples = classForm->reltuples;
32503213
vactuples = tabentry->n_dead_tuples;
32513214
instuples = tabentry->inserts_since_vacuum;
32523215
anltuples = tabentry->changes_since_analyze;

0 commit comments

Comments
 (0)