溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

PostgreSQL中用于初始化查詢(xún)執(zhí)行計(jì)劃函數(shù)是哪個(gè)

發(fā)布時(shí)間:2021-11-10 15:43:35 來(lái)源:億速云 閱讀:248 作者:iii 欄目:關(guān)系型數(shù)據(jù)庫(kù)

本篇內(nèi)容主要講解“PostgreSQL中用于初始化查詢(xún)執(zhí)行計(jì)劃函數(shù)是哪個(gè)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“PostgreSQL中用于初始化查詢(xún)執(zhí)行計(jì)劃函數(shù)是哪個(gè)”吧!

一、數(shù)據(jù)結(jié)構(gòu)

EState
執(zhí)行器在調(diào)用時(shí)的主要工作狀態(tài)

/* ----------------
 *    EState information
 *    EState信息
 * Master working state for an Executor invocation
 * 執(zhí)行器在調(diào)用時(shí)的主要工作狀態(tài)
 * ----------------
 */
typedef struct EState
{
    NodeTag     type;//標(biāo)記

    /* Basic state for all query types: */
    //所有查詢(xún)類(lèi)型的基礎(chǔ)狀態(tài)
    ScanDirection es_direction; /* 掃描方向,如向前/后等;current scan direction */
    Snapshot    es_snapshot;    /* 時(shí)間條件(通過(guò)快照實(shí)現(xiàn));time qual to use */
    Snapshot    es_crosscheck_snapshot; /* RI的交叉檢查時(shí)間條件;crosscheck time qual for RI */
    List       *es_range_table; /* RTE鏈表;List of RangeTblEntry */
    struct RangeTblEntry **es_range_table_array;    /* 與鏈表等價(jià)的數(shù)組;equivalent array */
    Index       es_range_table_size;    /* 數(shù)組大小;size of the range table arrays */
    Relation   *es_relations;   /* RTE中的Relation指針,如未Open則為NULL;
                                 * Array of per-range-table-entry Relation
                                 * pointers, or NULL if not yet opened */
    struct ExecRowMark **es_rowmarks;   /* ExecRowMarks指針數(shù)組;
                                         * Array of per-range-table-entry
                                         * ExecRowMarks, or NULL if none */
    PlannedStmt *es_plannedstmt;    /* 計(jì)劃樹(shù)的最頂層PlannedStmt;link to top of plan tree */
    const char *es_sourceText;  /* QueryDesc中的源文本;Source text from QueryDesc */

    JunkFilter *es_junkFilter;  /* 最頂層的JunkFilter;top-level junk filter, if any */

    /* If query can insert/delete tuples, the command ID to mark them with */
    //如查詢(xún)可以插入/刪除元組,這里記錄了命令I(lǐng)D
    CommandId   es_output_cid;

    /* Info about target table(s) for insert/update/delete queries: */
    //insert/update/delete 目標(biāo)表信息
    ResultRelInfo *es_result_relations; /* ResultRelInfos數(shù)組;array of ResultRelInfos */
    int         es_num_result_relations;    /* 數(shù)組大小;length of array */
    ResultRelInfo *es_result_relation_info; /* 當(dāng)前活動(dòng)的數(shù)組;currently active array elt */

    /*
     * Info about the partition root table(s) for insert/update/delete queries
     * targeting partitioned tables.  Only leaf partitions are mentioned in
     * es_result_relations, but we need access to the roots for firing
     * triggers and for runtime tuple routing.
     * 關(guān)于針對(duì)分區(qū)表的插入/更新/刪除查詢(xún)的分區(qū)根表的信息。
     * 在es_result_relations中只提到了葉子分區(qū),但是需要訪問(wèn)根表來(lái)觸發(fā)觸發(fā)器和運(yùn)行時(shí)元組路由。
     */
    ResultRelInfo *es_root_result_relations;    /* ResultRelInfos數(shù)組;array of ResultRelInfos */
    int         es_num_root_result_relations;   /* 數(shù)組大小;length of the array */

    /*
     * The following list contains ResultRelInfos created by the tuple routing
     * code for partitions that don't already have one.
     * 下面的鏈表包含元組路由代碼為沒(méi)有分區(qū)的分區(qū)創(chuàng)建的ResultRelInfos。
     */
    List       *es_tuple_routing_result_relations;

    /* Stuff used for firing triggers: */
    //用于觸發(fā)觸發(fā)器的信息
    List       *es_trig_target_relations;   /* 與觸發(fā)器相關(guān)的ResultRelInfos數(shù)組;trigger-only ResultRelInfos */
    TupleTableSlot *es_trig_tuple_slot; /* 用于觸發(fā)器輸出的元組; for trigger output tuples */
    TupleTableSlot *es_trig_oldtup_slot;    /* 用于TriggerEnabled;for TriggerEnabled */
    TupleTableSlot *es_trig_newtup_slot;    /* 用于TriggerEnabled;for TriggerEnabled */

    /* Parameter info: */
    //參數(shù)信息
    ParamListInfo es_param_list_info;   /* 外部參數(shù)值; values of external params */
    ParamExecData *es_param_exec_vals;  /* 內(nèi)部參數(shù)值; values of internal params */

    QueryEnvironment *es_queryEnv;  /* 查詢(xún)環(huán)境; query environment */

    /* Other working state: */
    //其他工作狀態(tài)
    MemoryContext es_query_cxt; /* EState所在的內(nèi)存上下文;per-query context in which EState lives */

    List       *es_tupleTable;  /* TupleTableSlots鏈表;List of TupleTableSlots */

    uint64      es_processed;   /* 處理的元組數(shù);# of tuples processed */
    Oid         es_lastoid;     /* 最后處理的oid(用于INSERT命令);last oid processed (by INSERT) */

    int         es_top_eflags;  /* 傳遞給ExecutorStart函數(shù)的eflags參數(shù);eflags passed to ExecutorStart */
    int         es_instrument;  /* InstrumentOption標(biāo)記;OR of InstrumentOption flags */
    bool        es_finished;    /* ExecutorFinish函數(shù)已完成則為T(mén);true when ExecutorFinish is done */

    List       *es_exprcontexts;    /* EState中的ExprContexts鏈表;List of ExprContexts within EState */

    List       *es_subplanstates;   /* SubPlans的PlanState鏈表;List of PlanState for SubPlans */

    List       *es_auxmodifytables; /* 第二個(gè)ModifyTableStates鏈表;List of secondary ModifyTableStates */

    /*
     * this ExprContext is for per-output-tuple operations, such as constraint
     * checks and index-value computations.  It will be reset for each output
     * tuple.  Note that it will be created only if needed.
     * 這個(gè)ExprContext用于元組輸出操作,例如約束檢查和索引值計(jì)算。它在每個(gè)輸出元組時(shí)重置。
     * 注意,只有在需要時(shí)才會(huì)創(chuàng)建它。
     */
    ExprContext *es_per_tuple_exprcontext;

    /*
     * These fields are for re-evaluating plan quals when an updated tuple is
     * substituted in READ COMMITTED mode.  es_epqTuple[] contains tuples that
     * scan plan nodes should return instead of whatever they'd normally
     * return, or NULL if nothing to return; es_epqTupleSet[] is true if a
     * particular array entry is valid; and es_epqScanDone[] is state to
     * remember if the tuple has been returned already.  Arrays are of size
     * es_range_table_size and are indexed by scan node scanrelid - 1.
     * 這些字段用于在讀取提交模式中替換更新后的元組時(shí)重新評(píng)估計(jì)劃的條件quals。
     * es_epqTuple[]數(shù)組包含掃描計(jì)劃節(jié)點(diǎn)應(yīng)該返回的元組,而不是它們通常返回的任何值,如果沒(méi)有返回值,則為NULL;
     * 如果特定數(shù)組條目有效,則es_epqTupleSet[]為真;es_epqScanDone[]是狀態(tài),用來(lái)記住元組是否已經(jīng)返回。
     * 數(shù)組大小為es_range_table_size,通過(guò)掃描節(jié)點(diǎn)scanrelid - 1進(jìn)行索引。
     */
    HeapTuple  *es_epqTuple;    /* EPQ替換元組的數(shù)組;array of EPQ substitute tuples */
    bool       *es_epqTupleSet; /* 如EPQ元組已提供,則為T(mén);true if EPQ tuple is provided */
    bool       *es_epqScanDone; /* 如EPQ元組已獲取,則為T(mén);true if EPQ tuple has been fetched */

    bool        es_use_parallel_mode;   /* 能否使用并行worker?can we use parallel workers? */

    /* The per-query shared memory area to use for parallel execution. */
    //用于并行執(zhí)行的每個(gè)查詢(xún)共享內(nèi)存區(qū)域。
    struct dsa_area *es_query_dsa;

    /*
     * JIT information. es_jit_flags indicates whether JIT should be performed
     * and with which options.  es_jit is created on-demand when JITing is
     * performed.
     * JIT的信息。es_jit_flags指示是否應(yīng)該執(zhí)行JIT以及使用哪些選項(xiàng)。在執(zhí)行JITing時(shí),按需創(chuàng)建es_jit。
     *
     * es_jit_combined_instr is the the combined, on demand allocated,
     * instrumentation from all workers. The leader's instrumentation is kept
     * separate, and is combined on demand by ExplainPrintJITSummary().
     * es_jit_combined_instr是所有workers根據(jù)需要分配的組合工具。
     * leader的插裝是獨(dú)立的,根據(jù)需要由ExplainPrintJITSummary()組合。
     */
    int         es_jit_flags;
    struct JitContext *es_jit;
    struct JitInstrumentation *es_jit_worker_instr;
} EState;

PlanState
PlanState是所有PlanState-type節(jié)點(diǎn)的虛父類(lèi)(請(qǐng)參照面向?qū)ο蟮奶擃?lèi))

/* ----------------
 *      PlanState node
 *      PlanState節(jié)點(diǎn)
 * We never actually instantiate any PlanState nodes; this is just the common
 * abstract superclass for all PlanState-type nodes.
 * 實(shí)際上并沒(méi)有實(shí)例化PlanState節(jié)點(diǎn);
 * 這是所有PlanState-type節(jié)點(diǎn)的虛父類(lèi)(請(qǐng)參照面向?qū)ο蟮奶擃?lèi)).
 * ----------------
 */
typedef struct PlanState
{
    NodeTag     type;//節(jié)點(diǎn)類(lèi)型

    Plan       *plan;           /* 綁定的計(jì)劃節(jié)點(diǎn);associated Plan node */

    EState     *state;          /* 在執(zhí)行期,指向top-level計(jì)劃的EState指針
                                 * at execution time, states of individual
                                 * nodes point to one EState for the whole
                                 * top-level plan */

    ExecProcNodeMtd ExecProcNode;   /* 執(zhí)行返回下一個(gè)元組的函數(shù);function to return next tuple */
    ExecProcNodeMtd ExecProcNodeReal;   /* 如果ExecProcNode是封裝器,則這個(gè)變量是實(shí)際的函數(shù);
                                         * actual function, if above is a
                                         * wrapper */

    Instrumentation *instrument;    /* 該節(jié)點(diǎn)可選的運(yùn)行期統(tǒng)計(jì)信息;Optional runtime stats for this node */
    WorkerInstrumentation *worker_instrument;   /* 每個(gè)worker的instrumentation;per-worker instrumentation */

    /* Per-worker JIT instrumentation */
    //worker相應(yīng)的JIT instrumentation
    struct SharedJitInstrumentation *worker_jit_instrument;

    /*
     * Common structural data for all Plan types.  These links to subsidiary
     * state trees parallel links in the associated plan tree (except for the
     * subPlan list, which does not exist in the plan tree).
     * 所有Plan類(lèi)型均有的數(shù)據(jù)結(jié)構(gòu);
     * 這些鏈接到附屬狀態(tài)通過(guò)并行的方式鏈接到關(guān)聯(lián)的計(jì)劃樹(shù)中(除了計(jì)劃樹(shù)中不存在的子計(jì)劃鏈表)。
     */
    ExprState  *qual;           /* 布爾條件;boolean qual condition */
    struct PlanState *lefttree; /* 輸入的計(jì)劃樹(shù),包括左樹(shù)&右樹(shù);input plan tree(s) */
    struct PlanState *righttree;

    List       *initPlan;       /* 初始的SubPlanState節(jié)點(diǎn)鏈表;
                                 * Init SubPlanState nodes (un-correlated expr
                                 * subselects) */
    List       *subPlan;        /* 在表達(dá)式中的subPlan鏈表;SubPlanState nodes in my expressions */

    /*
     * State for management of parameter-change-driven rescanning
     * 參數(shù)改變驅(qū)動(dòng)的重新掃描管理狀態(tài)
     */
    Bitmapset  *chgParam;       /* changed Params的IDs集合(用于NestLoop連接);set of IDs of changed Params */

    /*
     * Other run-time state needed by most if not all node types.
     * 大多數(shù)(如果不是所有)節(jié)點(diǎn)類(lèi)型都需要的其他運(yùn)行時(shí)狀態(tài)。
     */
    TupleDesc ps_ResultTupleDesc;   /* 節(jié)點(diǎn)的返回類(lèi)型;node's return type */
    TupleTableSlot *ps_ResultTupleSlot; /* 結(jié)果元組的slot;slot for my result tuples */
    ExprContext *ps_ExprContext;    /* 節(jié)點(diǎn)的表達(dá)式解析上下文;node's expression-evaluation context */
    ProjectionInfo *ps_ProjInfo;    /* 元組投影信息;info for doing tuple projection */

    /*
     * Scanslot's descriptor if known. This is a bit of a hack, but otherwise
     * it's hard for expression compilation to optimize based on the
     * descriptor, without encoding knowledge about all executor nodes.
     * Scanslot描述符。
     * 這有點(diǎn)笨拙,但是如果不編碼關(guān)于所有執(zhí)行器節(jié)點(diǎn)的知識(shí),那么表達(dá)式編譯就很難基于描述符進(jìn)行優(yōu)化。
     */
    TupleDesc   scandesc;
} PlanState;

二、源碼解讀

InitPlan函數(shù)初始化查詢(xún)執(zhí)行計(jì)劃:打開(kāi)文件/分配存儲(chǔ)空間并啟動(dòng)規(guī)則管理器.

/* ----------------------------------------------------------------
 *      InitPlan
 *
 *      Initializes the query plan: open files, allocate storage
 *      and start up the rule manager
 *      初始化查詢(xún)執(zhí)行計(jì)劃:打開(kāi)文件/分配存儲(chǔ)空間并啟動(dòng)規(guī)則管理器
 * ----------------------------------------------------------------
 */
static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
    CmdType     operation = queryDesc->operation;//命令類(lèi)型
    PlannedStmt *plannedstmt = queryDesc->plannedstmt;//已規(guī)劃的語(yǔ)句指針
    Plan       *plan = plannedstmt->planTree;//計(jì)劃樹(shù)
    List       *rangeTable = plannedstmt->rtable;//RTE鏈表
    EState     *estate = queryDesc->estate;//參見(jiàn)數(shù)據(jù)結(jié)構(gòu)
    PlanState  *planstate;//參見(jiàn)數(shù)據(jù)結(jié)構(gòu)
    TupleDesc   tupType;//參見(jiàn)數(shù)據(jù)結(jié)構(gòu)
    ListCell   *l;
    int         i;

    /*
     * Do permissions checks
     * 權(quán)限檢查
     */
    ExecCheckRTPerms(rangeTable, true);

    /*
     * initialize the node's execution state
     * 初始化節(jié)點(diǎn)執(zhí)行狀態(tài)
     */
    ExecInitRangeTable(estate, rangeTable);

    estate->es_plannedstmt = plannedstmt;

    /*
     * Initialize ResultRelInfo data structures, and open the result rels.
     * 初始化ResultRelInfo數(shù)據(jù)結(jié)構(gòu),打開(kāi)結(jié)果rels
     */
    if (plannedstmt->resultRelations)//存在resultRelations
    {
        List       *resultRelations = plannedstmt->resultRelations;//結(jié)果Relation鏈表
        int         numResultRelations = list_length(resultRelations);//鏈表大小
        ResultRelInfo *resultRelInfos;//ResultRelInfo數(shù)組
        ResultRelInfo *resultRelInfo;//ResultRelInfo指針

        resultRelInfos = (ResultRelInfo *)
            palloc(numResultRelations * sizeof(ResultRelInfo));//分配空間
        resultRelInfo = resultRelInfos;//指針賦值
        foreach(l, resultRelations)//遍歷鏈表
        {
            Index       resultRelationIndex = lfirst_int(l);
            Relation    resultRelation;

            resultRelation = ExecGetRangeTableRelation(estate,
                                                       resultRelationIndex);//獲取結(jié)果Relation
            InitResultRelInfo(resultRelInfo,
                              resultRelation,
                              resultRelationIndex,
                              NULL,
                              estate->es_instrument);//初始化ResultRelInfo
            resultRelInfo++;//處理下一個(gè)ResultRelInfo
        }
        estate->es_result_relations = resultRelInfos;//賦值
        estate->es_num_result_relations = numResultRelations;

        /* es_result_relation_info is NULL except when within ModifyTable */
        //設(shè)置es_result_relation_info為NULL,除了ModifyTable
        estate->es_result_relation_info = NULL;

        /*
         * In the partitioned result relation case, also build ResultRelInfos
         * for all the partitioned table roots, because we will need them to
         * fire statement-level triggers, if any.
         * 在分區(qū)結(jié)果關(guān)系這種情況中,還為所有分區(qū)表根構(gòu)建ResultRelInfos,
         * 因?yàn)槲覀冃枰鼈冇|發(fā)語(yǔ)句級(jí)別的觸發(fā)器(如果有的話(huà))。
         */
        if (plannedstmt->rootResultRelations)//存在rootResultRelations(并行處理)
        {
            int         num_roots = list_length(plannedstmt->rootResultRelations);

            resultRelInfos = (ResultRelInfo *)
                palloc(num_roots * sizeof(ResultRelInfo));
            resultRelInfo = resultRelInfos;
            foreach(l, plannedstmt->rootResultRelations)
            {
                Index       resultRelIndex = lfirst_int(l);
                Relation    resultRelDesc;

                resultRelDesc = ExecGetRangeTableRelation(estate,
                                                          resultRelIndex);
                InitResultRelInfo(resultRelInfo,
                                  resultRelDesc,
                                  resultRelIndex,
                                  NULL,
                                  estate->es_instrument);
                resultRelInfo++;
            }

            estate->es_root_result_relations = resultRelInfos;
            estate->es_num_root_result_relations = num_roots;
        }
        else
        {
            estate->es_root_result_relations = NULL;
            estate->es_num_root_result_relations = 0;
        }
    }
    else//不存在resultRelations
    {
        /*
         * if no result relation, then set state appropriately
         * 無(wú)resultRelations,設(shè)置相應(yīng)的信息為NULL或?yàn)?
         */
        estate->es_result_relations = NULL;
        estate->es_num_result_relations = 0;
        estate->es_result_relation_info = NULL;
        estate->es_root_result_relations = NULL;
        estate->es_num_root_result_relations = 0;
    }

    /*
     * Next, build the ExecRowMark array from the PlanRowMark(s), if any.
     * 下一步,利用PlanRowMark(s)創(chuàng)建ExecRowMark數(shù)組
     */
    if (plannedstmt->rowMarks)//如存在rowMarks
    {
        estate->es_rowmarks = (ExecRowMark **)
            palloc0(estate->es_range_table_size * sizeof(ExecRowMark *));
        foreach(l, plannedstmt->rowMarks)
        {
            PlanRowMark *rc = (PlanRowMark *) lfirst(l);
            Oid         relid;
            Relation    relation;
            ExecRowMark *erm;

            /* ignore "parent" rowmarks; they are irrelevant at runtime */
            if (rc->isParent)
                continue;

            /* get relation's OID (will produce InvalidOid if subquery) */
            relid = exec_rt_fetch(rc->rti, estate)->relid;

            /* open relation, if we need to access it for this mark type */
            switch (rc->markType)
            {
                case ROW_MARK_EXCLUSIVE:
                case ROW_MARK_NOKEYEXCLUSIVE:
                case ROW_MARK_SHARE:
                case ROW_MARK_KEYSHARE:
                case ROW_MARK_REFERENCE:
                    relation = ExecGetRangeTableRelation(estate, rc->rti);
                    break;
                case ROW_MARK_COPY:
                    /* no physical table access is required */
                    relation = NULL;
                    break;
                default:
                    elog(ERROR, "unrecognized markType: %d", rc->markType);
                    relation = NULL;    /* keep compiler quiet */
                    break;
            }

            /* Check that relation is a legal target for marking */
            if (relation)
                CheckValidRowMarkRel(relation, rc->markType);

            erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
            erm->relation = relation;
            erm->relid = relid;
            erm->rti = rc->rti;
            erm->prti = rc->prti;
            erm->rowmarkId = rc->rowmarkId;
            erm->markType = rc->markType;
            erm->strength = rc->strength;
            erm->waitPolicy = rc->waitPolicy;
            erm->ermActive = false;
            ItemPointerSetInvalid(&(erm->curCtid));
            erm->ermExtra = NULL;

            Assert(erm->rti > 0 && erm->rti <= estate->es_range_table_size &&
                   estate->es_rowmarks[erm->rti - 1] == NULL);

            estate->es_rowmarks[erm->rti - 1] = erm;
        }
    }

    /*
     * Initialize the executor's tuple table to empty.
     * 初始化執(zhí)行器的元組表為NULL
     */
    estate->es_tupleTable = NIL;
    estate->es_trig_tuple_slot = NULL;
    estate->es_trig_oldtup_slot = NULL;
    estate->es_trig_newtup_slot = NULL;

    /* mark EvalPlanQual not active */
    //標(biāo)記EvalPlanQual為非活動(dòng)模式
    estate->es_epqTuple = NULL;
    estate->es_epqTupleSet = NULL;
    estate->es_epqScanDone = NULL;

    /*
     * Initialize private state information for each SubPlan.  We must do this
     * before running ExecInitNode on the main query tree, since
     * ExecInitSubPlan expects to be able to find these entries.
     * 為每個(gè)子計(jì)劃初始化私有狀態(tài)信息。
     * 在主查詢(xún)樹(shù)上運(yùn)行ExecInitNode之前,必須這樣做,因?yàn)镋xecInitSubPlan希望能夠找到這些條目。
     */
    Assert(estate->es_subplanstates == NIL);
    i = 1;                      /* subplan索引計(jì)數(shù)從1開(kāi)始;subplan indices count from 1 */
    foreach(l, plannedstmt->subplans)//遍歷subplans
    {
        Plan       *subplan = (Plan *) lfirst(l);
        PlanState  *subplanstate;
        int         sp_eflags;

        /*
         * A subplan will never need to do BACKWARD scan nor MARK/RESTORE. If
         * it is a parameterless subplan (not initplan), we suggest that it be
         * prepared to handle REWIND efficiently; otherwise there is no need.
         * 子計(jì)劃永遠(yuǎn)不需要執(zhí)行向后掃描或標(biāo)記/恢復(fù)。
         * 如果它是一個(gè)無(wú)參數(shù)的子計(jì)劃(不是initplan),建議它準(zhǔn)備好有效地處理向后掃描;否則就沒(méi)有必要了。
         */
        sp_eflags = eflags
            & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA);//設(shè)置sp_eflags
        if (bms_is_member(i, plannedstmt->rewindPlanIDs))
            sp_eflags |= EXEC_FLAG_REWIND;

        subplanstate = ExecInitNode(subplan, estate, sp_eflags);//執(zhí)行Plan節(jié)點(diǎn)初始化過(guò)程

        estate->es_subplanstates = lappend(estate->es_subplanstates,
                                           subplanstate);

        i++;
    }

    /*
     * Initialize the private state information for all the nodes in the query
     * tree.  This opens files, allocates storage and leaves us ready to start
     * processing tuples.
     * 為查詢(xún)樹(shù)中的所有節(jié)點(diǎn)初始化私有狀態(tài)信息。
     * 這將打開(kāi)文件、分配存儲(chǔ)并讓我們準(zhǔn)備好開(kāi)始處理元組。
     */
    planstate = ExecInitNode(plan, estate, eflags);//執(zhí)行Plan節(jié)點(diǎn)初始化過(guò)程

    /*
     * Get the tuple descriptor describing the type of tuples to return.
     * 獲取元組描述(返回的元組類(lèi)型等)
     */
    tupType = ExecGetResultType(planstate);

    /*
     * Initialize the junk filter if needed.  SELECT queries need a filter if
     * there are any junk attrs in the top-level tlist.
     * 如需要,初始化垃圾過(guò)濾器。如果頂層的tlist中有任何垃圾標(biāo)識(shí),SELECT查詢(xún)需要一個(gè)過(guò)濾器。
     */
    if (operation == CMD_SELECT)//SELECT命令
    {
        bool        junk_filter_needed = false;
        ListCell   *tlist;

        foreach(tlist, plan->targetlist)//遍歷tlist
        {
            TargetEntry *tle = (TargetEntry *) lfirst(tlist);

            if (tle->resjunk)//如需要垃圾過(guò)濾器
            {
                junk_filter_needed = true;//設(shè)置為T(mén)
                break;
            }
        }

        if (junk_filter_needed)
        {
            JunkFilter *j;

            j = ExecInitJunkFilter(planstate->plan->targetlist,
                                   tupType->tdhasoid,
                                   ExecInitExtraTupleSlot(estate, NULL));//初始化
            estate->es_junkFilter = j;

            /* Want to return the cleaned tuple type */
            //期望返回已清理的元組類(lèi)型
            tupType = j->jf_cleanTupType;
        }
    }
    //賦值
    queryDesc->tupDesc = tupType;
    queryDesc->planstate = planstate;
}

三、跟蹤分析

測(cè)試腳本如下

testdb=# explain select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je 
testdb-# from t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je 
testdb(#                         from t_grxx gr inner join t_jfxx jf 
testdb(#                                        on gr.dwbh = dw.dwbh 
testdb(#                                           and gr.grbh = jf.grbh) grjf
testdb-# order by dw.dwbh;
                                        QUERY PLAN                                        
------------------------------------------------------------------------------------------
 Sort  (cost=20070.93..20320.93 rows=100000 width=47)
   Sort Key: dw.dwbh
   ->  Hash Join  (cost=3754.00..8689.61 rows=100000 width=47)
         Hash Cond: ((gr.dwbh)::text = (dw.dwbh)::text)
         ->  Hash Join  (cost=3465.00..8138.00 rows=100000 width=31)
               Hash Cond: ((jf.grbh)::text = (gr.grbh)::text)
               ->  Seq Scan on t_jfxx jf  (cost=0.00..1637.00 rows=100000 width=20)
               ->  Hash  (cost=1726.00..1726.00 rows=100000 width=16)
                     ->  Seq Scan on t_grxx gr  (cost=0.00..1726.00 rows=100000 width=16)
         ->  Hash  (cost=164.00..164.00 rows=10000 width=20)
               ->  Seq Scan on t_dwxx dw  (cost=0.00..164.00 rows=10000 width=20)
(11 rows)

啟動(dòng)gdb,設(shè)置斷點(diǎn),進(jìn)入InitPlan

(gdb) b InitPlan
Breakpoint 1 at 0x6d9df2: file execMain.c, line 808.
(gdb) c
Continuing.

Breakpoint 1, InitPlan (queryDesc=0x20838b8, eflags=16) at execMain.c:808
warning: Source file is more recent than executable.
808     CmdType     operation = queryDesc->operation;

輸入?yún)?shù)

(gdb) p *queryDesc
$1 = {operation = CMD_SELECT, plannedstmt = 0x207e6c0, 
  sourceText = 0x1f96eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>..., 
  snapshot = 0x1fba8e0, crosscheck_snapshot = 0x0, dest = 0xf8f280 <donothingDR>, params = 0x0, queryEnv = 0x0, 
  instrument_options = 0, tupDesc = 0x0, estate = 0x207f898, planstate = 0x0, already_executed = false, totaltime = 0x0}
(gdb) p eflags
$2 = 16

變量賦值,PlannedStmt的詳細(xì)數(shù)據(jù)結(jié)構(gòu)先前章節(jié)已有解釋,請(qǐng)參見(jiàn)相關(guān)章節(jié).

(gdb) n
809     PlannedStmt *plannedstmt = queryDesc->plannedstmt;
(gdb) 
810     Plan       *plan = plannedstmt->planTree;
(gdb) 
811     List       *rangeTable = plannedstmt->rtable;
(gdb) n
812     EState     *estate = queryDesc->estate;
(gdb) 
821     ExecCheckRTPerms(rangeTable, true);
(gdb) p *plannedstmt
$3 = {type = T_PlannedStmt, commandType = CMD_SELECT, queryId = 0, hasReturning = false, hasModifyingCTE = false, 
  canSetTag = true, transientPlan = false, dependsOnRole = false, parallelModeNeeded = false, jitFlags = 0, 
  planTree = 0x20788f8, rtable = 0x207c568, resultRelations = 0x0, nonleafResultRelations = 0x0, rootResultRelations = 0x0, 
  subplans = 0x0, rewindPlanIDs = 0x0, rowMarks = 0x0, relationOids = 0x207c5c8, invalItems = 0x0, paramExecTypes = 0x0, 
  utilityStmt = 0x0, stmt_location = 0, stmt_len = 313}
(gdb) p *plan
$4 = {type = T_Sort, startup_cost = 20070.931487218411, total_cost = 20320.931487218411, plan_rows = 100000, 
  plan_width = 47, parallel_aware = false, parallel_safe = true, plan_node_id = 0, targetlist = 0x207cc28, qual = 0x0, 
  lefttree = 0x207c090, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}
(gdb) p *estate
$5 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x1fba8e0, es_crosscheck_snapshot = 0x0, 
  es_range_table = 0x0, es_plannedstmt = 0x0, 
  es_sourceText = 0x1f96eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>..., 
  es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x0, es_num_result_relations = 0, 
  es_result_relation_info = 0x0, es_root_result_relations = 0x0, es_num_root_result_relations = 0, 
  es_tuple_routing_result_relations = 0x0, es_trig_target_relations = 0x0, es_trig_tuple_slot = 0x0, 
  es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0, es_param_exec_vals = 0x0, 
  es_queryEnv = 0x0, es_query_cxt = 0x207f780, es_tupleTable = 0x0, es_rowMarks = 0x0, es_processed = 0, es_lastoid = 0, 
  es_top_eflags = 16, es_instrument = 0, es_finished = false, es_exprcontexts = 0x0, es_subplanstates = 0x0, 
  es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epqTuple = 0x0, es_epqTupleSet = 0x0, es_epqScanDone = 0x0, 
  es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 0, es_jit = 0x0, es_jit_worker_instr = 0x0}

RTE鏈表,一共有5個(gè)Item,3個(gè)基礎(chǔ)關(guān)系RTE_RELATION(1/3/4),1個(gè)RTE_SUBQUERY(2號(hào)),1個(gè)RTE_JOIN(5號(hào))

(gdb) n
826     estate->es_range_table = rangeTable;
(gdb) p *rangeTable
$6 = {type = T_List, length = 5, head = 0x207c540, tail = 0x207cb28}
(gdb) p *(RangeTblEntry *)rangeTable->head->data.ptr_value
$9 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 16734, relkind = 114 'r', tablesample = 0x0, subquery = 0x0, 
  security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0, funcordinality = false, 
  tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, self_reference = false, coltypes = 0x0, 
  coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, enrtuples = 0, alias = 0x1f98448, eref = 0x1fbdd20, 
  lateral = false, inh = false, inFromCl = true, requiredPerms = 2, checkAsUser = 0, selectedCols = 0x2054de8, 
  insertedCols = 0x0, updatedCols = 0x0, securityQuals = 0x0}
...

沒(méi)有結(jié)果Relation,執(zhí)行相應(yīng)的處理邏輯

(gdb) 
835     if (plannedstmt->resultRelations)
(gdb) p plannedstmt->resultRelations
$14 = (List *) 0x0
(gdb) n
922         estate->es_result_relations = NULL;
(gdb) 
923         estate->es_num_result_relations = 0;
(gdb) 
924         estate->es_result_relation_info = NULL;
(gdb) 
925         estate->es_root_result_relations = NULL;
(gdb) 
926         estate->es_num_root_result_relations = 0;

不存在rowMarks(for update)

(gdb) n
939     foreach(l, plannedstmt->rowMarks)
(gdb) p plannedstmt->rowMarks
$15 = (List *) 0x0
(gdb) p plannedstmt->rowMarks
$16 = (List *) 0x0
(gdb) n
1000        estate->es_tupleTable = NIL;

執(zhí)行賦值

(gdb) n
1001        estate->es_trig_tuple_slot = NULL;
(gdb) 
1002        estate->es_trig_oldtup_slot = NULL;
...

沒(méi)有subplans

(gdb) n
1017        foreach(l, plannedstmt->subplans)
(gdb) p *plannedstmt->subplans
Cannot access memory at address 0x0
(gdb) n

初始化節(jié)點(diǎn)(執(zhí)行ExecInitNode)和獲取TupleType

(gdb) n
1046        planstate = ExecInitNode(plan, estate, eflags);
(gdb) n
1051        tupType = ExecGetResultType(planstate);
(gdb) 
1057        if (operation == CMD_SELECT)
(gdb) p *planstate
$17 = {type = T_SortState, plan = 0x20788f8, state = 0x207f898, ExecProcNode = 0x6e41bb <ExecProcNodeFirst>, 
  ExecProcNodeReal = 0x716144 <ExecSort>, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, 
  qual = 0x0, lefttree = 0x207fbc8, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, 
  ps_ResultTupleSlot = 0x2090dc0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x208e920}
(gdb) p tupType
$18 = (TupleDesc) 0x20909a8
(gdb) p *tupType
$19 = {natts = 7, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x20909c8}

判斷是否需要垃圾過(guò)濾器

(gdb) n
1059            bool        junk_filter_needed = false;
(gdb) 
1062            foreach(tlist, plan->targetlist)

不需要junk filter

(gdb) 
1073            if (junk_filter_needed)

賦值,結(jié)束調(diào)用

(gdb) 
1087        queryDesc->tupDesc = tupType;
(gdb) 
1088        queryDesc->planstate = planstate;
(gdb) 
1089    }
(gdb) 
standard_ExecutorStart (queryDesc=0x20838b8, eflags=16) at execMain.c:267
267     MemoryContextSwitchTo(oldcontext);
(gdb) p *queryDesc
$21 = {operation = CMD_SELECT, plannedstmt = 0x207e6c0, 
  sourceText = 0x1f96eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>..., 
  snapshot = 0x1fba8e0, crosscheck_snapshot = 0x0, dest = 0xf8f280 <donothingDR>, params = 0x0, queryEnv = 0x0, 
  instrument_options = 0, tupDesc = 0x20909a8, estate = 0x207f898, planstate = 0x207fab0, already_executed = false, 
  totaltime = 0x0}

到此,相信大家對(duì)“PostgreSQL中用于初始化查詢(xún)執(zhí)行計(jì)劃函數(shù)是哪個(gè)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI