diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index eeba2caa43..9298e03add 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -8024,6 +8024,66 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; + + autovacuum_analyze_attach_partition (boolean) + + autovacuum_analyze_attach_partition + configuration parameter + + + + + Controls whether ATTACH PARTITION commands are counted + as the changed tuples for partitioned tables. The default value is on. + If on, the number of tuples of the attached partition is counted in its + ancestors' changed tuples. + This parameter can only be set in the postgresql.conf + file or on the server command line; but this can be + disabled for individual tables by changing table storage parameters. + + + + + + autovacuum_analyze_detach_partition (boolean) + + autovacuum_analyze_detach_partition + configuration parameter + + + + + Controls whether DETACH PARTITION commands are counted + as the changed tuples for partitioned tables. The default value is on. + If on, the number of tuples of the detached partition is counted in its + ancestors' changed tuples. + This parameter can only be set in the postgresql.conf + file or on the server command line; but this can be + disabled for individual tables by changing table storage parameters. + + + + + + autovacuum_analyze_drop_partition (boolean) + + autovacuum_analyze_drop_partition + configuration parameter + + + + + Controls whether DROP TABLE commands executed on partitions + are counted as the changed tuples for partitioned tables. The default value is + on. If on, the number of tuples of the dropped partition is counted in its + ancestors' changed tuples. + This parameter can only be set in the postgresql.conf + file or on the server command line; but this can be + disabled for individual tables by changing table storage parameters. + + + + diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index 4b535809b6..b3faec97e4 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -818,10 +818,17 @@ analyze threshold = analyze base threshold + analyze scale factor * number of tu is compared to the total number of tuples inserted, updated, or deleted since the last ANALYZE. For partitioned tables, inserts, updates and deletes on partitions - are counted towards this threshold; however, DDL - operations such as ATTACH, DETACH - and DROP are not, so running a manual - ANALYZE is recommended if the partition added or + are counted towards this threshold. + In the case of DDL operations such as + ATTACH, DETACH and DROP, + the number of tuples of partitions is counted instead. They are controled + by , + and + , respectively. + The default values are on; but when autovacuum_analyze_attach_partition, + autovacuum_analyze_detach_partition and + autovacuum_analyze_drop_partition are set to off, + running a manual ANALYZE is recommended if the partition added or removed contains a statistically significant volume of data. diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index c6d0a35e50..ad2aa2f8b9 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -1733,6 +1733,48 @@ WITH ( MODULUS numeric_literal, REM + + autovacuum_analyze_attach_partition (boolean) + + autovacuum_analyze_attach_partition storage parameter + + + + + Per-table value + for parameter. + + + + + + autovacuum_analyze_detach_partition (boolean) + + autovacuum_analyze_detach_partition storage parameter + + + + + Per-table value + for parameter. + + + + + + autovacuum_analyze_drop_partition (boolean) + + autovacuum_analyze_drop_partition storage parameter + + + + + Per-table value + for parameter. + + + + log_autovacuum_min_duration, toast.log_autovacuum_min_duration (integer) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 5554275e64..45ad2b882e 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -160,6 +160,33 @@ static relopt_bool boolRelOpts[] = }, { { + "autovacuum_analyze_attach_partition", + "Count ATTACH PARTITION commands as row updates", + RELOPT_KIND_PARTITIONED, + AccessExclusiveLock + }, + true + }, + { + { + "autovacuum_analyze_detach_partition", + "Count DETACH PARTITION commands as row updates", + RELOPT_KIND_PARTITIONED, + AccessExclusiveLock + }, + true + }, + { + { + "autovacuum_analyze_drop_partition", + "Counts DROP TABLE commands executed on partitions as row updates", + RELOPT_KIND_PARTITIONED, + AccessExclusiveLock + }, + true + }, + { + { "deduplicate_items", "Enables \"deduplicate items\" feature for this btree index", RELOPT_KIND_BTREE, @@ -1852,6 +1879,12 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)}, {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)}, + {"autovacuum_analyze_attach_partition", RELOPT_TYPE_BOOL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_attach_partition)}, + {"autovacuum_analyze_detach_partition", RELOPT_TYPE_BOOL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_detach_partition)}, + {"autovacuum_analyze_drop_partition", RELOPT_TYPE_BOOL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_drop_partition)}, {"user_catalog_table", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, @@ -1962,8 +1995,10 @@ bytea * partitioned_table_reloptions(Datum reloptions, bool validate) { /* - * autovacuum_enabled, autovacuum_analyze_threshold and - * autovacuum_analyze_scale_factor are supported for partitioned tables. + * autovacuum_enabled, autovacuum_analyze_threshold, + * autovacuum_analyze_scale_factor, autovacuum_analyze_attach_partition, + * autovacuum_analyze_detach_partition and autovacuum_analyze_drop_partition + * are supported for partitioned tables. */ return default_reloptions(reloptions, validate, RELOPT_KIND_PARTITIONED); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 1293dc04ca..3d89783f99 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -74,6 +74,7 @@ #include "parser/parse_relation.h" #include "parser/parsetree.h" #include "partitioning/partdesc.h" +#include "pgstat.h" #include "storage/lmgr.h" #include "storage/predicate.h" #include "storage/smgr.h" @@ -2028,6 +2029,11 @@ heap_drop_with_catalog(Oid relid) RelationForgetRelation(relid); /* + * update changes_since_analyze of its ancestors for auto ANALYZE + */ + pgstat_report_anl_ancestors(relid, false, false, true); + + /* * remove inheritance information */ RelationRemoveInheritance(relid); diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 426c1e6710..f49498c495 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -694,7 +694,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params, onerel->rd_rel->relkind == RELKIND_RELATION && onerel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT) { - pgstat_report_anl_ancestors(RelationGetRelid(onerel)); + pgstat_report_anl_ancestors(RelationGetRelid(onerel), false, false, false); } /* diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 4e23c7fce5..37a7b43383 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -17312,6 +17312,9 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel)); + /* update changes_since_analyze of its ancestors for auto ANALYZE */ + pgstat_report_anl_ancestors(RelationGetRelid(attachrel), true, false, false); + /* keep our lock until commit */ table_close(attachrel, NoLock); @@ -17859,6 +17862,9 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, RemoveInheritance(partRel, rel, true); } + /* update changes_since_analyze of its ancestors for auto ANALYZE */ + pgstat_report_anl_ancestors(RelationGetRelid(partRel), false, true, false); + /* Drop any triggers that were cloned on creation/attach. */ DropClonedTriggersFromPartition(RelationGetRelid(partRel)); diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index d516df0ac5..dd7455f787 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -128,6 +128,10 @@ int autovacuum_multixact_freeze_max_age; double autovacuum_vac_cost_delay; int autovacuum_vac_cost_limit; +bool autovacuum_anl_attach_partition = false; +bool autovacuum_anl_detach_partition = false; +bool autovacuum_anl_drop_partition = false; + int Log_autovacuum_min_duration = -1; /* how long to keep pgstat data in the launcher, in milliseconds */ @@ -2100,7 +2104,7 @@ do_autovacuum(void) tabentry->changes_since_analyze - tabentry->changes_since_analyze_reported > 0) { - pgstat_report_anl_ancestors(relid); + pgstat_report_anl_ancestors(relid, false, false, false); updated = true; } } diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index b0d07c0e0b..bd469dbcfc 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -1667,11 +1667,15 @@ pgstat_report_analyze(Relation rel, * * Send list of partitioned table ancestors of the given partition to the * collector. The collector is in charge of propagating the analyze tuple - * counts from the partition to its ancestors. This is necessary so that - * other processes can decide whether to analyze the partitioned tables. + * counts from the partition to its ancestors. The attached, detached + * and dropped flags indicate whether this fuction is called by ATTACH/DETACH + * PARTITION and DROP TABLE command, respectively. If either flag is TRUE, + * the collector will propagate the partition's livetuples to its ancestors' + * analyze tuple counts. This is necessary so that other processes can + * decide whether to analyze the partitioned tables. */ void -pgstat_report_anl_ancestors(Oid relid) +pgstat_report_anl_ancestors(Oid relid, bool attached, bool detached, bool dropped) { PgStat_MsgAnlAncestors msg; List *ancestors; @@ -1680,12 +1684,33 @@ pgstat_report_anl_ancestors(Oid relid) pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANL_ANCESTORS); msg.m_databaseid = MyDatabaseId; msg.m_tableoid = relid; + msg.m_count_livetuples = (attached || detached || dropped) ? true : false; + msg.m_reset_reportedcounter = detached; msg.m_nancestors = 0; ancestors = get_partition_ancestors(relid); foreach(lc, ancestors) { Oid ancestor = lfirst_oid(lc); + Relation ancestorRel; + AutoVacOpts *avopts; + + ancestorRel = table_open(ancestor, AccessShareLock); + avopts = ancestorRel->rd_options + ? &(((StdRdOptions *) ancestorRel->rd_options)->autovacuum) + : NULL; + + /* Check reloptions */ + if ((attached && (avopts ? !avopts->analyze_attach_partition + : !autovacuum_anl_attach_partition)) || + (detached && (avopts ? !avopts->analyze_detach_partition + : !autovacuum_anl_detach_partition)) || + (dropped && (avopts ? !avopts->analyze_drop_partition + : !autovacuum_anl_drop_partition))) + { + table_close(ancestorRel, AccessShareLock); + continue; + } msg.m_ancestors[msg.m_nancestors] = ancestor; if (++msg.m_nancestors >= PGSTAT_NUM_ANCESTORENTRIES) @@ -1694,6 +1719,8 @@ pgstat_report_anl_ancestors(Oid relid) msg.m_nancestors * sizeof(Oid)); msg.m_nancestors = 0; } + + table_close(ancestorRel, AccessShareLock); } if (msg.m_nancestors > 0) @@ -5301,12 +5328,20 @@ pgstat_recv_anl_ancestors(PgStat_MsgAnlAncestors *msg, int len) PgStat_StatTabEntry *ancestor; ancestor = pgstat_get_tab_entry(dbentry, ancestor_relid, true); - ancestor->changes_since_analyze += - tabentry->changes_since_analyze - tabentry->changes_since_analyze_reported; - } - tabentry->changes_since_analyze_reported = tabentry->changes_since_analyze; + if (msg->m_count_livetuples) + ancestor->changes_since_analyze += + tabentry->n_live_tuples - tabentry->changes_since_analyze_reported; + else + ancestor->changes_since_analyze += + tabentry->changes_since_analyze - tabentry->changes_since_analyze_reported; + } + /* Reset changes_since_analyze_reported to zero if the partition is detached */ + if (msg->m_reset_reportedcounter) + tabentry->changes_since_analyze_reported = 0; + else + tabentry->changes_since_analyze_reported = tabentry->changes_since_analyze; } /* ---------- diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 68b62d523d..f2068e22d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1569,7 +1569,33 @@ static struct config_bool ConfigureNamesBool[] = true, NULL, NULL, NULL }, - + { + {"autovacuum_analyze_attach_partition", PGC_SIGHUP, AUTOVACUUM, + gettext_noop("Count ATTACH PARTITION commands as row updates."), + NULL, + }, + &autovacuum_anl_attach_partition, + true, + NULL, NULL, NULL + }, + { + {"autovacuum_analyze_detach_partition", PGC_SIGHUP, AUTOVACUUM, + gettext_noop("Count DETACH PARTITION commands as row updates."), + NULL, + }, + &autovacuum_anl_detach_partition, + true, + NULL, NULL, NULL + }, + { + {"autovacuum_analyze_drop_partition", PGC_SIGHUP, AUTOVACUUM, + gettext_noop("Count DROP TABLE commands executed on partitions as row updates."), + NULL, + }, + &autovacuum_anl_drop_partition, + true, + NULL, NULL, NULL + }, { {"trace_notify", PGC_USERSET, DEVELOPER_OPTIONS, gettext_noop("Generates debugging output for LISTEN and NOTIFY."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index ddbb6dc2be..4b603af5f9 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -643,6 +643,12 @@ #autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for # autovacuum, -1 means use # vacuum_cost_limit +#autovacuum_analyze_attach_partition = on # count ATTACH PARTITION commands + # as row updates +#autovacuum_analyze_detach_partition = on # count DETACH PARTITION commands + # as row updates +#autovacuum_analyze_drop_partition = on # count DROP TABLE commands executed + # on partitions as row updates #------------------------------------------------------------------------------ diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index bd8e9ea2f8..7f6a5b933b 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1099,6 +1099,9 @@ static const pgsql_thing_t words_after_create[] = { /* Storage parameters for CREATE TABLE and ALTER TABLE */ static const char *const table_storage_parameters[] = { + "autovacuum_analyze_attach_partition", + "autovacuum_analyze_detach_partition", + "autovacuum_analyze_drop_partition", "autovacuum_analyze_scale_factor", "autovacuum_analyze_threshold", "autovacuum_enabled", diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 9612c0a6c2..644fb40d85 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -438,7 +438,7 @@ typedef struct PgStat_MsgAnalyze * ---------- */ #define PGSTAT_NUM_ANCESTORENTRIES \ - ((PGSTAT_MSG_PAYLOAD - sizeof(Oid) - sizeof(Oid) - sizeof(int)) \ + ((PGSTAT_MSG_PAYLOAD - 2 * sizeof(Oid) - 2 * sizeof(bool) - sizeof(int)) \ / sizeof(Oid)) typedef struct PgStat_MsgAnlAncestors @@ -446,6 +446,8 @@ typedef struct PgStat_MsgAnlAncestors PgStat_MsgHdr m_hdr; Oid m_databaseid; Oid m_tableoid; + bool m_count_livetuples; + bool m_reset_reportedcounter; int m_nancestors; Oid m_ancestors[PGSTAT_NUM_ANCESTORENTRIES]; } PgStat_MsgAnlAncestors; @@ -1002,7 +1004,8 @@ extern void pgstat_report_vacuum(Oid tableoid, bool shared, extern void pgstat_report_analyze(Relation rel, PgStat_Counter livetuples, PgStat_Counter deadtuples, bool resetcounter); -extern void pgstat_report_anl_ancestors(Oid relid); +extern void pgstat_report_anl_ancestors(Oid relid, + bool attached, bool detached, bool dropped); extern void pgstat_report_recovery_conflict(int reason); extern void pgstat_report_deadlock(void); diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index aacdd0f575..2cbb53d1b3 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -41,6 +41,9 @@ extern int autovacuum_freeze_max_age; extern int autovacuum_multixact_freeze_max_age; extern double autovacuum_vac_cost_delay; extern int autovacuum_vac_cost_limit; +extern bool autovacuum_anl_attach_partition; +extern bool autovacuum_anl_detach_partition; +extern bool autovacuum_anl_drop_partition; /* autovacuum launcher PID, only valid when worker is shutting down */ extern int AutovacuumLauncherPid; diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 774ac5b2b1..e479bd3f87 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -305,6 +305,9 @@ typedef struct AutoVacOpts float8 vacuum_scale_factor; float8 vacuum_ins_scale_factor; float8 analyze_scale_factor; + bool analyze_attach_partition; + bool analyze_detach_partition; + bool analyze_drop_partition; } AutoVacOpts; typedef struct StdRdOptions