Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0e69f70

Browse filesBrowse 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
Copy full SHA for 0e69f70

File tree

Expand file treeCollapse file tree

3 files changed

+59
-39
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+59
-39
lines changed

‎src/backend/commands/analyze.c

Copy file name to clipboardExpand all lines: src/backend/commands/analyze.c
+12Lines changed: 12 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: src/backend/commands/tablecmds.c
+46-1Lines changed: 46 additions & 1 deletion
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

Copy file name to clipboardExpand all lines: src/backend/postmaster/autovacuum.c
+1-38Lines changed: 1 addition & 38 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.