PostgreSQL中vacuum主流程分析

66次阅读
没有评论

共计 6135 个字符,预计需要花费 16 分钟才能阅读完成。

本篇内容介绍了“PostgreSQL 中 vacuum 主流程分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、数据结构

宏定义
Vacuum 和 Analyze 命令选项

/* ----------------------
 * Vacuum and Analyze Statements
 * Vacuum 和 Analyze 命令选项
 * 
 * Even though these are nominally two statements, it s convenient to use
 * just one node type for both. Note that at least one of VACOPT_VACUUM
 * and VACOPT_ANALYZE must be set in options.
 *  虽然在这里有两种不同的语句, 但只需要使用统一的 Node 类型即可.
 *  注意至少 VACOPT_VACUUM/VACOPT_ANALYZE 在选项中设置.
 * ----------------------
 */
typedef enum VacuumOption
 VACOPT_VACUUM = 1   0, /* do VACUUM */
 VACOPT_ANALYZE = 1   1, /* do ANALYZE */
 VACOPT_VERBOSE = 1   2, /* print progress info */
 VACOPT_FREEZE = 1   3, /* FREEZE option */
 VACOPT_FULL = 1   4, /* FULL (non-concurrent) vacuum */
 VACOPT_SKIP_LOCKED = 1   5, /* skip if cannot get lock */
 VACOPT_SKIPTOAST = 1   6, /* don t process the TOAST table, if any */
 VACOPT_DISABLE_PAGE_SKIPPING = 1   7 /* don t skip any pages */
} VacuumOption;

VacuumStmt
存储 vacuum 命令的 option Relation 链表

typedef struct VacuumStmt
 NodeTag type;//Tag
 //VacuumOption 位标记
 int options; /* OR of VacuumOption flags */
 //VacuumRelation 链表, 如为 NIL-- 所有 Relation.
 List *rels; /* list of VacuumRelation, or NIL for all */
} VacuumStmt;

VacuumParams
vacuum 命令参数

/*
 * Parameters customizing behavior of VACUUM and ANALYZE.
 *  客户端调用 VACUUM/ANALYZE 时的定制化参数
 */
typedef struct VacuumParams
 // 最小 freeze age,- 1 表示使用默认
 int freeze_min_age; /* min freeze age, -1 to use default */
 // 扫描整个 table 的 freeze age
 int freeze_table_age; /* age at which to scan whole table */
 // 最小的 multixact freeze age,- 1 表示默认
 int multixact_freeze_min_age; /* min multixact freeze age, -1 to
 * use default */
 // 扫描全表的 freeze age,- 1 表示默认
 int multixact_freeze_table_age; /* multixact age at which to scan
 * whole table */
 // 是否强制 wraparound?
 bool is_wraparound; /* force a for-wraparound vacuum */
 // 以毫秒为单位的最小执行阈值
 int log_min_duration; /* minimum execution threshold in ms at
 * which verbose logs are activated, -1
 * to use default */
} VacuumParams;

VacuumRelation
VACUUM/ANALYZE 命令的目标表信息

/*
 * Info about a single target table of VACUUM/ANALYZE.
 * VACUUM/ANALYZE 命令的目标表信息.
 * 
 * If the OID field is set, it always identifies the table to process.
 * Then the relation field can be NULL; if it isn t, it s used only to report
 * failure to open/lock the relation.
 *  如设置了 OID 字段, 该值通常是将要处理的数据表.
 *  那么关系字段可以为空; 如果不是,则仅用于报告未能打开 / 锁定关系。 */
typedef struct VacuumRelation
 NodeTag type;
 RangeVar *relation; /* table name to process, or NULL */
 Oid oid; /* table s OID; InvalidOid if not looked up */
 List *va_cols; /* list of column names, or NIL for all */
} VacuumRelation;

二、源码解读

ExecVacuum 函数, 手工执行 VACUUM/ANALYZE 命令时的主入口,vacuum() 函数的包装器 (wrapper).

/*
 * Primary entry point for manual VACUUM and ANALYZE commands
 *  手工执行 VACUUM/ANALYZE 命令时的主入口
 *
 * This is mainly a preparation wrapper for the real operations that will
 * happen in vacuum().
 *  这是 vacuum() 函数的包装器 (wrapper)
 */
ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel)
 VacuumParams params;
 /* sanity checks on options */
 // 验证 检查
 Assert(vacstmt- options   (VACOPT_VACUUM | VACOPT_ANALYZE));
 Assert((vacstmt- options   VACOPT_VACUUM) ||
 !(vacstmt- options   (VACOPT_FULL | VACOPT_FREEZE)));
 Assert(!(vacstmt- options   VACOPT_SKIPTOAST));
 /*
 * Make sure VACOPT_ANALYZE is specified if any column lists are present.
 *  如出现字段列表, 则确保指定了 VACOPT_ANALYZE 选项
 */
 if (!(vacstmt- options   VACOPT_ANALYZE))
 {
 ListCell *lc;
 foreach(lc, vacstmt- rels)
 { VacuumRelation *vrel = lfirst_node(VacuumRelation, lc);
 if (vrel- va_cols != NIL)
 ereport(ERROR,
 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 errmsg(ANALYZE option must be specified when a column list is provided)));
 }
 }
 /*
 * All freeze ages are zero if the FREEZE option is given; otherwise pass
 * them as -1 which means to use the default values.
 *  如指定了 FREEZE 选项则设置所有 freeze ages 为 0.
 *  否则的话, 传递 -1(即使用默认值).
 */
 if (vacstmt- options   VACOPT_FREEZE)
 {
 // 指定 VACOPT_FREEZE
 params.freeze_min_age = 0;
 params.freeze_table_age = 0;
 params.multixact_freeze_min_age = 0;
 params.multixact_freeze_table_age = 0;
 }
 else
 {
 params.freeze_min_age = -1;
 params.freeze_table_age = -1;
 params.multixact_freeze_min_age = -1;
 params.multixact_freeze_table_age = -1;
 }
 /* user-invoked vacuum is never  for wraparound  */
 // 用户调用的 vacuum 永远不会是 wraparound
 params.is_wraparound = false;
 /* user-invoked vacuum never uses this parameter */
 // 用户调用 vacuum 永远不会使用该参数
 params.log_min_duration = -1;
 /* Now go through the common routine */
 // 调用 vacuum
 vacuum(vacstmt- options, vacstmt- rels,  params, NULL, isTopLevel);
}

三、跟踪分析

测试脚本

17:19:28 (xdb@[local]:5432)testdb=# vacuum t1;

启动 gdb, 设置断点

(gdb) b ExecVacuum
Breakpoint 1 at 0x6b99a1: file vacuum.c, line 92.
(gdb) c
Continuing.
Breakpoint 1, ExecVacuum (vacstmt=0x210e9c0, isTopLevel=true) at vacuum.c:92
92 Assert(vacstmt- options   (VACOPT_VACUUM | VACOPT_ANALYZE));
(gdb)

输入参数
options = 1 — VACOPT_VACUUM

(gdb) p *vacstmt
$1 = {type = T_VacuumStmt, options = 1, rels = 0x210e988}
(gdb)

获取 Relation 相关信息

gdb) n
93 Assert((vacstmt- options   VACOPT_VACUUM) ||
(gdb) 
95 Assert(!(vacstmt- options   VACOPT_SKIPTOAST));
(gdb) 
100 if (!(vacstmt- options   VACOPT_ANALYZE))
(gdb) 
104 foreach(lc, vacstmt- rels)
(gdb) 
106 VacuumRelation *vrel = lfirst_node(VacuumRelation, lc);
(gdb) 
108 if (vrel- va_cols != NIL)
(gdb) p *vrel
$3 = {type = T_VacuumRelation, relation = 0x210e8d0, oid = 0, va_cols = 0x0}
(gdb) p *vrel- relation
$4 = {type = T_RangeVar, catalogname = 0x0, schemaname = 0x0, relname = 0x210e8b0  t1 , inh = true, 
 relpersistence = 112  p , alias = 0x0, location = 7}
(gdb)

设置 vacuum 参数

(gdb) n
104 foreach(lc, vacstmt- rels)
(gdb) 
119 if (vacstmt- options   VACOPT_FREEZE)
(gdb) 
128 params.freeze_min_age = -1;
(gdb) 
129 params.freeze_table_age = -1;
(gdb) 
130 params.multixact_freeze_min_age = -1;
(gdb) 
131 params.multixact_freeze_table_age = -1;
(gdb) 
135 params.is_wraparound = false;
(gdb) 
(gdb) n
138 params.log_min_duration = -1;
(gdb)

调用 vacuum

141 vacuum(vacstmt- options, vacstmt- rels,  params, NULL, isTopLevel);
(gdb) 
142 }
(gdb) 
standard_ProcessUtility (pstmt=0x210ea80, queryString=0x210dec8  vacuum t1; , context=PROCESS_UTILITY_TOPLEVEL, params=0x0, 
 queryEnv=0x0, dest=0x210ed70, completionTag=0x7fff1d69dea0  ) at utility.c:672
672 break;

“PostgreSQL 中 vacuum 主流程分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-24发表,共计6135字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)