千家信息网

PostgreSQL中vacuum主流程分析

发表于:2024-11-26 作者:千家信息网编辑
千家信息网最后更新 2024年11月26日,本篇内容介绍了"PostgreSQL中vacuum主流程分析"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有
千家信息网最后更新 2024年11月26日PostgreSQL中vacuum主流程分析

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

一、数据结构

宏定义
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) */voidExecVacuum(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, ¶ms, NULL, isTopLevel);}

三、跟踪分析

测试脚本

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

启动gdb,设置断点

(gdb) b ExecVacuumBreakpoint 1 at 0x6b99a1: file vacuum.c, line 92.(gdb) cContinuing.Breakpoint 1, ExecVacuum (vacstmt=0x210e9c0, isTopLevel=true) at vacuum.c:9292      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) n93      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) n104         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) n138     params.log_min_duration = -1;(gdb)

调用vacuum

141     vacuum(vacstmt->options, vacstmt->rels, ¶ms, 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:672672             break;

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

0