您好,登錄后才能下訂單哦!
本篇內(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è)”吧!
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í)!
免責(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)容。