您好,登錄后才能下訂單哦!
這篇文章主要介紹“PostgreSQL中什么函數(shù)通過(guò)遞歸調(diào)用初始化計(jì)劃樹(shù)中的所有Plan節(jié)點(diǎn)”,在日常操作中,相信很多人在PostgreSQL中什么函數(shù)通過(guò)遞歸調(diào)用初始化計(jì)劃樹(shù)中的所有Plan節(jié)點(diǎn)問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”P(pán)ostgreSQL中什么函數(shù)通過(guò)遞歸調(diào)用初始化計(jì)劃樹(shù)中的所有Plan節(jié)點(diǎn)”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
Plan
所有計(jì)劃節(jié)點(diǎn)通過(guò)將Plan結(jié)構(gòu)作為第一個(gè)字段從Plan結(jié)構(gòu)“派生”。這確保了在將節(jié)點(diǎn)轉(zhuǎn)換為計(jì)劃節(jié)點(diǎn)時(shí),一切都能正常工作。(在執(zhí)行器中以通用方式傳遞時(shí),節(jié)點(diǎn)指針經(jīng)常被轉(zhuǎn)換為Plan *)
/* ---------------- * Plan node * * All plan nodes "derive" from the Plan structure by having the * Plan structure as the first field. This ensures that everything works * when nodes are cast to Plan's. (node pointers are frequently cast to Plan* * when passed around generically in the executor) * 所有計(jì)劃節(jié)點(diǎn)通過(guò)將Plan結(jié)構(gòu)作為第一個(gè)字段從Plan結(jié)構(gòu)“派生”。 * 這確保了在將節(jié)點(diǎn)轉(zhuǎn)換為計(jì)劃節(jié)點(diǎn)時(shí),一切都能正常工作。 * (在執(zhí)行器中以通用方式傳遞時(shí),節(jié)點(diǎn)指針經(jīng)常被轉(zhuǎn)換為Plan *) * * We never actually instantiate any Plan nodes; this is just the common * abstract superclass for all Plan-type nodes. * 從未實(shí)例化任何Plan節(jié)點(diǎn);這只是所有Plan-type節(jié)點(diǎn)的通用抽象超類。 * ---------------- */ typedef struct Plan { NodeTag type;//節(jié)點(diǎn)類型 /* * 成本估算信息;estimated execution costs for plan (see costsize.c for more info) */ Cost startup_cost; /* 啟動(dòng)成本;cost expended before fetching any tuples */ Cost total_cost; /* 總成本;total cost (assuming all tuples fetched) */ /* * 優(yōu)化器估算信息;planner's estimate of result size of this plan step */ double plan_rows; /* 行數(shù);number of rows plan is expected to emit */ int plan_width; /* 平均行大小(Byte為單位);average row width in bytes */ /* * 并行執(zhí)行相關(guān)的信息;information needed for parallel query */ bool parallel_aware; /* 是否參與并行執(zhí)行邏輯?engage parallel-aware logic? */ bool parallel_safe; /* 是否并行安全;OK to use as part of parallel plan? */ /* * Plan類型節(jié)點(diǎn)通用的信息.Common structural data for all Plan types. */ int plan_node_id; /* unique across entire final plan tree */ List *targetlist; /* target list to be computed at this node */ List *qual; /* implicitly-ANDed qual conditions */ struct Plan *lefttree; /* input plan tree(s) */ struct Plan *righttree; List *initPlan; /* Init Plan nodes (un-correlated expr * subselects) */ /* * Information for management of parameter-change-driven rescanning * parameter-change-driven重掃描的管理信息. * * extParam includes the paramIDs of all external PARAM_EXEC params * affecting this plan node or its children. setParam params from the * node's initPlans are not included, but their extParams are. * * allParam includes all the extParam paramIDs, plus the IDs of local * params that affect the node (i.e., the setParams of its initplans). * These are _all_ the PARAM_EXEC params that affect this node. */ Bitmapset *extParam; Bitmapset *allParam; } Plan;
ExecInitNode函數(shù)遞歸初始化計(jì)劃樹(shù)中的所有Plan節(jié)點(diǎn),返回對(duì)應(yīng)給定的Plan Node節(jié)點(diǎn)的PlanState節(jié)點(diǎn).
/* ------------------------------------------------------------------------ * ExecInitNode * * Recursively initializes all the nodes in the plan tree rooted * at 'node'. * 遞歸初始化計(jì)劃樹(shù)中的所有Plan節(jié)點(diǎn). * * Inputs: * 'node' is the current node of the plan produced by the query planner * 'estate' is the shared execution state for the plan tree * 'eflags' is a bitwise OR of flag bits described in executor.h * node-查詢計(jì)劃器產(chǎn)生的當(dāng)前節(jié)點(diǎn) * estate-Plan樹(shù)共享的執(zhí)行狀態(tài)信息 * eflags-一個(gè)位或標(biāo)記位,在executor.h中描述 * * Returns a PlanState node corresponding to the given Plan node. * 返回對(duì)應(yīng)Plan Node節(jié)點(diǎn)的PlanState節(jié)點(diǎn) * ------------------------------------------------------------------------ */ PlanState * ExecInitNode(Plan *node, EState *estate, int eflags) { PlanState *result;//結(jié)果 List *subps;//子PlanState鏈表 ListCell *l;//臨時(shí)變量 /* * do nothing when we get to the end of a leaf on tree. * 如node為NULL則返回NULL */ if (node == NULL) return NULL; /* * Make sure there's enough stack available. Need to check here, in * addition to ExecProcNode() (via ExecProcNodeFirst()), to ensure the * stack isn't overrun while initializing the node tree. * 確保有足夠的堆??捎谩? * 除了ExecProcNode()(通過(guò)ExecProcNodeFirst()調(diào)用),還需要在這里進(jìn)行檢查,以確保在初始化節(jié)點(diǎn)樹(shù)時(shí)堆棧沒(méi)有溢出。 */ check_stack_depth(); switch (nodeTag(node))//根據(jù)節(jié)點(diǎn)類型進(jìn)入相應(yīng)的邏輯 { /* * 控制節(jié)點(diǎn);control nodes */ case T_Result: result = (PlanState *) ExecInitResult((Result *) node, estate, eflags); break; case T_ProjectSet: result = (PlanState *) ExecInitProjectSet((ProjectSet *) node, estate, eflags); break; case T_ModifyTable: result = (PlanState *) ExecInitModifyTable((ModifyTable *) node, estate, eflags); break; case T_Append: result = (PlanState *) ExecInitAppend((Append *) node, estate, eflags); break; case T_MergeAppend: result = (PlanState *) ExecInitMergeAppend((MergeAppend *) node, estate, eflags); break; case T_RecursiveUnion: result = (PlanState *) ExecInitRecursiveUnion((RecursiveUnion *) node, estate, eflags); break; case T_BitmapAnd: result = (PlanState *) ExecInitBitmapAnd((BitmapAnd *) node, estate, eflags); break; case T_BitmapOr: result = (PlanState *) ExecInitBitmapOr((BitmapOr *) node, estate, eflags); break; /* * 掃描節(jié)點(diǎn);scan nodes */ case T_SeqScan: result = (PlanState *) ExecInitSeqScan((SeqScan *) node, estate, eflags); break; case T_SampleScan: result = (PlanState *) ExecInitSampleScan((SampleScan *) node, estate, eflags); break; case T_IndexScan: result = (PlanState *) ExecInitIndexScan((IndexScan *) node, estate, eflags); break; case T_IndexOnlyScan: result = (PlanState *) ExecInitIndexOnlyScan((IndexOnlyScan *) node, estate, eflags); break; case T_BitmapIndexScan: result = (PlanState *) ExecInitBitmapIndexScan((BitmapIndexScan *) node, estate, eflags); break; case T_BitmapHeapScan: result = (PlanState *) ExecInitBitmapHeapScan((BitmapHeapScan *) node, estate, eflags); break; case T_TidScan: result = (PlanState *) ExecInitTidScan((TidScan *) node, estate, eflags); break; case T_SubqueryScan: result = (PlanState *) ExecInitSubqueryScan((SubqueryScan *) node, estate, eflags); break; case T_FunctionScan: result = (PlanState *) ExecInitFunctionScan((FunctionScan *) node, estate, eflags); break; case T_TableFuncScan: result = (PlanState *) ExecInitTableFuncScan((TableFuncScan *) node, estate, eflags); break; case T_ValuesScan: result = (PlanState *) ExecInitValuesScan((ValuesScan *) node, estate, eflags); break; case T_CteScan: result = (PlanState *) ExecInitCteScan((CteScan *) node, estate, eflags); break; case T_NamedTuplestoreScan: result = (PlanState *) ExecInitNamedTuplestoreScan((NamedTuplestoreScan *) node, estate, eflags); break; case T_WorkTableScan: result = (PlanState *) ExecInitWorkTableScan((WorkTableScan *) node, estate, eflags); break; case T_ForeignScan: result = (PlanState *) ExecInitForeignScan((ForeignScan *) node, estate, eflags); break; case T_CustomScan: result = (PlanState *) ExecInitCustomScan((CustomScan *) node, estate, eflags); break; /* * 連接節(jié)點(diǎn)/join nodes */ case T_NestLoop: result = (PlanState *) ExecInitNestLoop((NestLoop *) node, estate, eflags); break; case T_MergeJoin: result = (PlanState *) ExecInitMergeJoin((MergeJoin *) node, estate, eflags); break; case T_HashJoin: result = (PlanState *) ExecInitHashJoin((HashJoin *) node, estate, eflags); break; /* * 物化節(jié)點(diǎn)/materialization nodes */ case T_Material: result = (PlanState *) ExecInitMaterial((Material *) node, estate, eflags); break; case T_Sort: result = (PlanState *) ExecInitSort((Sort *) node, estate, eflags); break; case T_Group: result = (PlanState *) ExecInitGroup((Group *) node, estate, eflags); break; case T_Agg: result = (PlanState *) ExecInitAgg((Agg *) node, estate, eflags); break; case T_WindowAgg: result = (PlanState *) ExecInitWindowAgg((WindowAgg *) node, estate, eflags); break; case T_Unique: result = (PlanState *) ExecInitUnique((Unique *) node, estate, eflags); break; case T_Gather: result = (PlanState *) ExecInitGather((Gather *) node, estate, eflags); break; case T_GatherMerge: result = (PlanState *) ExecInitGatherMerge((GatherMerge *) node, estate, eflags); break; case T_Hash: result = (PlanState *) ExecInitHash((Hash *) node, estate, eflags); break; case T_SetOp: result = (PlanState *) ExecInitSetOp((SetOp *) node, estate, eflags); break; case T_LockRows: result = (PlanState *) ExecInitLockRows((LockRows *) node, estate, eflags); break; case T_Limit: result = (PlanState *) ExecInitLimit((Limit *) node, estate, eflags); break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); result = NULL; /* 避免優(yōu)化器提示警告信息;keep compiler quiet */ break; } //設(shè)置節(jié)點(diǎn)的ExecProcNode函數(shù) ExecSetExecProcNode(result, result->ExecProcNode); /* * Initialize any initPlans present in this node. The planner put them in * a separate list for us. * 初始化該P(yáng)lan節(jié)點(diǎn)中的所有initPlans. * 計(jì)劃器把這些信息放到一個(gè)單獨(dú)的鏈表中 */ subps = NIL;//初始化 foreach(l, node->initPlan)//遍歷initPlan { SubPlan *subplan = (SubPlan *) lfirst(l);//子計(jì)劃 SubPlanState *sstate;//子計(jì)劃狀態(tài) Assert(IsA(subplan, SubPlan)); sstate = ExecInitSubPlan(subplan, result);//初始化SubPlan subps = lappend(subps, sstate);//添加到鏈表中 } result->initPlan = subps;//賦值 /* Set up instrumentation for this node if requested */ //如需要,配置instrumentation if (estate->es_instrument) result->instrument = InstrAlloc(1, estate->es_instrument); return result; } /* * If a node wants to change its ExecProcNode function after ExecInitNode() * has finished, it should do so with this function. That way any wrapper * functions can be reinstalled, without the node having to know how that * works. * 如果一個(gè)節(jié)點(diǎn)想要在ExecInitNode()完成之后更改它的ExecProcNode函數(shù),那么它應(yīng)該使用這個(gè)函數(shù)。 * 這樣就可以重新安裝任何包裝器函數(shù),而不必讓節(jié)點(diǎn)知道它是如何工作的。 */ void ExecSetExecProcNode(PlanState *node, ExecProcNodeMtd function) { /* * Add a wrapper around the ExecProcNode callback that checks stack depth * during the first execution and maybe adds an instrumentation wrapper. * When the callback is changed after execution has already begun that * means we'll superfluously execute ExecProcNodeFirst, but that seems ok. * 在ExecProcNode回調(diào)函數(shù)添加一個(gè)包裝器,在第一次執(zhí)行時(shí)檢查堆棧深度,可能還會(huì)添加一個(gè)檢測(cè)包裝器。 * 在執(zhí)行已經(jīng)開(kāi)始之后,當(dāng)回調(diào)函數(shù)被更改時(shí),這意味著再次執(zhí)行ExecProcNodeFirst是多余的,但這似乎是可以的。 */ node->ExecProcNodeReal = function; node->ExecProcNode = ExecProcNodeFirst; } /* ---------------------------------------------------------------- * ExecInitSeqScan * 初始化順序掃描節(jié)點(diǎn) * ---------------------------------------------------------------- */ SeqScanState * ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) { SeqScanState *scanstate; /* * Once upon a time it was possible to have an outerPlan of a SeqScan, but * not any more. * 先前有可能存在外部的SeqScan計(jì)劃,但現(xiàn)在該做法已廢棄,這里進(jìn)行校驗(yàn) */ Assert(outerPlan(node) == NULL); Assert(innerPlan(node) == NULL); /* * create state structure * 創(chuàng)建SeqScanState數(shù)據(jù)結(jié)構(gòu)體 */ scanstate = makeNode(SeqScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; scanstate->ss.ps.ExecProcNode = ExecSeqScan; /* * Miscellaneous initialization * 初始化 * create expression context for node * 創(chuàng)建表達(dá)式上下文 */ ExecAssignExprContext(estate, &scanstate->ss.ps); /* * open the scan relation * 打開(kāi)掃描的Relation */ scanstate->ss.ss_currentRelation = ExecOpenScanRelation(estate, node->scanrelid, eflags); /* and create slot with the appropriate rowtype */ //使用合適的rowtype打開(kāi)slot ExecInitScanTupleSlot(estate, &scanstate->ss, RelationGetDescr(scanstate->ss.ss_currentRelation)); /* * Initialize result type and projection. * 初始化結(jié)果類型和投影 */ ExecInitResultTypeTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); /* * initialize child expressions * 初始化子表達(dá)式 */ scanstate->ss.ps.qual = ExecInitQual(node->plan.qual, (PlanState *) scanstate); return scanstate; } /* ---------------------------------------------------------------- * ExecOpenScanRelation * * Open the heap relation to be scanned by a base-level scan plan node. * This should be called during the node's ExecInit routine. * 打開(kāi)Heap Relation,由一個(gè)基表掃描計(jì)劃節(jié)點(diǎn)掃描。這應(yīng)該在節(jié)點(diǎn)的ExecInit例程中調(diào)用。 * ---------------------------------------------------------------- */ Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags) { Relation rel; /* Open the relation. */ //打開(kāi)關(guān)系 rel = ExecGetRangeTableRelation(estate, scanrelid); /* * Complain if we're attempting a scan of an unscannable relation, except * when the query won't actually be run. This is a slightly klugy place * to do this, perhaps, but there is no better place. * 給出提示信息:試圖掃描一個(gè)不存在的關(guān)系。這可能是一個(gè)有點(diǎn)笨拙的地方,但沒(méi)有更好的提示了。 */ if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 && !RelationIsScannable(rel)) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("materialized view \"%s\" has not been populated", RelationGetRelationName(rel)), errhint("Use the REFRESH MATERIALIZED VIEW command."))); return rel; } /* ---------------------------------------------------------------- * ExecInitHashJoin * 初始化Hash連接節(jié)點(diǎn) * Init routine for HashJoin node. * Hash連接通過(guò)遞歸調(diào)用ExecInitNode函數(shù)初始化參與連接的Relation * ---------------------------------------------------------------- */ HashJoinState * ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) { HashJoinState *hjstate; Plan *outerNode; Hash *hashNode; List *lclauses; List *rclauses; List *rhclauses; List *hoperators; TupleDesc outerDesc, innerDesc; ListCell *l; /* check for unsupported flags */ //校驗(yàn)不支持的flags Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); /* * create state structure * 創(chuàng)建state數(shù)據(jù)結(jié)構(gòu)體 */ hjstate = makeNode(HashJoinState); hjstate->js.ps.plan = (Plan *) node; hjstate->js.ps.state = estate; /* * See ExecHashJoinInitializeDSM() and ExecHashJoinInitializeWorker() * where this function may be replaced with a parallel version, if we * managed to launch a parallel query. * 請(qǐng)參閱ExecHashJoinInitializeWorker()和ExecHashJoinInitializeWorker(), * 如果成功啟動(dòng)了并行查詢,這個(gè)函數(shù)可以用一個(gè)并行版本替換。 */ hjstate->js.ps.ExecProcNode = ExecHashJoin; hjstate->js.jointype = node->join.jointype; /* * Miscellaneous initialization * 初始化 * create expression context for node */ ExecAssignExprContext(estate, &hjstate->js.ps); /* * initialize child nodes * 初始化子節(jié)點(diǎn) * * Note: we could suppress the REWIND flag for the inner input, which * would amount to betting that the hash will be a single batch. Not * clear if this would be a win or not. * 注意:可以禁止內(nèi)部輸入的REWIND標(biāo)志,這相當(dāng)于打賭散列將是單個(gè)批處理。 * 不清楚這是否會(huì)是一場(chǎng)勝利。 */ outerNode = outerPlan(node); hashNode = (Hash *) innerPlan(node); outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags);//遞歸處理外表節(jié)點(diǎn) outerDesc = ExecGetResultType(outerPlanState(hjstate));// innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags);//遞歸處理內(nèi)表節(jié)點(diǎn) innerDesc = ExecGetResultType(innerPlanState(hjstate)); /* * Initialize result slot, type and projection. * 初始化節(jié)點(diǎn)slot/類型和投影 */ ExecInitResultTupleSlotTL(&hjstate->js.ps); ExecAssignProjectionInfo(&hjstate->js.ps, NULL); /* * tuple table initialization * 元組表初始化 */ hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate, outerDesc); /* * detect whether we need only consider the first matching inner tuple * 檢測(cè)是否只需要考慮內(nèi)表元組的首次匹配 */ hjstate->js.single_match = (node->join.inner_unique || node->join.jointype == JOIN_SEMI); /* set up null tuples for outer joins, if needed */ //配置外連接的NULL元組 switch (node->join.jointype) { case JOIN_INNER: case JOIN_SEMI: break; case JOIN_LEFT: case JOIN_ANTI://左連接&半連接 hjstate->hj_NullInnerTupleSlot = ExecInitNullTupleSlot(estate, innerDesc); break; case JOIN_RIGHT: hjstate->hj_NullOuterTupleSlot = ExecInitNullTupleSlot(estate, outerDesc); break; case JOIN_FULL: hjstate->hj_NullOuterTupleSlot = ExecInitNullTupleSlot(estate, outerDesc); hjstate->hj_NullInnerTupleSlot = ExecInitNullTupleSlot(estate, innerDesc); break; default: elog(ERROR, "unrecognized join type: %d", (int) node->join.jointype); } /* * now for some voodoo. our temporary tuple slot is actually the result * tuple slot of the Hash node (which is our inner plan). we can do this * because Hash nodes don't return tuples via ExecProcNode() -- instead * the hash join node uses ExecScanHashBucket() to get at the contents of * the hash table. -cim 6/9/91 * 現(xiàn)在來(lái)點(diǎn)巫術(shù)。 * 臨時(shí)tuple槽實(shí)際上是散列節(jié)點(diǎn)的結(jié)果tuple槽(這是我們的內(nèi)部計(jì)劃)。 * 之可以這樣做,是因?yàn)楣9?jié)點(diǎn)不會(huì)通過(guò)ExecProcNode()返回元組—— * 相反,哈希連接節(jié)點(diǎn)使用ExecScanHashBucket()來(lái)獲取哈希表的內(nèi)容。 * by cim 6/9/91 */ { HashState *hashstate = (HashState *) innerPlanState(hjstate); TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot; hjstate->hj_HashTupleSlot = slot; } /* * initialize child expressions * 初始化子表達(dá)式 */ hjstate->js.ps.qual = ExecInitQual(node->join.plan.qual, (PlanState *) hjstate); hjstate->js.joinqual = ExecInitQual(node->join.joinqual, (PlanState *) hjstate); hjstate->hashclauses = ExecInitQual(node->hashclauses, (PlanState *) hjstate); /* * initialize hash-specific info * 初始化hash相關(guān)的信息 */ hjstate->hj_HashTable = NULL; hjstate->hj_FirstOuterTupleSlot = NULL; hjstate->hj_CurHashValue = 0; hjstate->hj_CurBucketNo = 0; hjstate->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO; hjstate->hj_CurTuple = NULL; /* * Deconstruct the hash clauses into outer and inner argument values, so * that we can evaluate those subexpressions separately. Also make a list * of the hash operator OIDs, in preparation for looking up the hash * functions to use. * 將哈希子句解構(gòu)為外部和內(nèi)部參數(shù)值,以便能夠分別計(jì)算這些子表達(dá)式。 * 還可以列出哈希運(yùn)算符oid,以便查找要使用的哈希函數(shù)。 */ lclauses = NIL; rclauses = NIL; rhclauses = NIL; hoperators = NIL; foreach(l, node->hashclauses) { OpExpr *hclause = lfirst_node(OpExpr, l); lclauses = lappend(lclauses, ExecInitExpr(linitial(hclause->args), (PlanState *) hjstate)); rclauses = lappend(rclauses, ExecInitExpr(lsecond(hclause->args), (PlanState *) hjstate)); rhclauses = lappend(rhclauses, ExecInitExpr(lsecond(hclause->args), innerPlanState(hjstate))); hoperators = lappend_oid(hoperators, hclause->opno); } hjstate->hj_OuterHashKeys = lclauses; hjstate->hj_InnerHashKeys = rclauses; hjstate->hj_HashOperators = hoperators; /* child Hash node needs to evaluate inner hash keys, too */ ((HashState *) innerPlanState(hjstate))->hashkeys = rhclauses; hjstate->hj_JoinState = HJ_BUILD_HASHTABLE; hjstate->hj_MatchedOuter = false; hjstate->hj_OuterNotEmpty = false; return hjstate; }
測(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)入ExecInitNode
(gdb) b ExecInitNode Breakpoint 1 at 0x6e3b90: file execProcnode.c, line 148. (gdb) c Continuing. Breakpoint 1, ExecInitNode (node=0x1b71f90, estate=0x1b78f48, eflags=16) at execProcnode.c:148 warning: Source file is more recent than executable. 148 if (node == NULL)
輸入?yún)?shù),node為T(mén)_Sort
(gdb) p *node $1 = {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 = 0x1b762c0, qual = 0x0, lefttree = 0x1b75728, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0} (gdb) p *estate $2 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x1b31e10, es_crosscheck_snapshot = 0x0, es_range_table = 0x1b75c00, es_plannedstmt = 0x1b77d58, es_sourceText = 0x1a8ceb8 "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 = 0x1b78e30, 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}
檢查堆棧
(gdb) n 156 check_stack_depth();
進(jìn)入相應(yīng)的處理邏輯
158 switch (nodeTag(node)) (gdb) 313 result = (PlanState *) ExecInitSort((Sort *) node,
返回結(jié)果
(gdb) p *result $3 = {type = 11084746, plan = 0x69900000699, state = 0x0, ExecProcNode = 0x0, ExecProcNodeReal = 0x0, instrument = 0x1000000000000, worker_instrument = 0x0, worker_jit_instrument = 0x200000001, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x7f7f7f7f7f7f7f7e, ps_ResultTupleSlot = 0x7f7f7f7f7f7f7f7f, ps_ExprContext = 0x7f7f7f7f7f7f7f7f, ps_ProjInfo = 0x80, scandesc = 0x0}
設(shè)置斷點(diǎn),進(jìn)入ExecSetExecProcNode
(gdb) b ExecSetExecProcNode Breakpoint 2 at 0x6e41a1: file execProcnode.c, line 414. (gdb) c Continuing.
ExecSetExecProcNode->輸入?yún)?shù),function為ExecSeqScan,在實(shí)際執(zhí)行時(shí)調(diào)用此函數(shù)
(gdb) p *function $5 = {TupleTableSlot *(struct PlanState *)} 0x714d59 <ExecSeqScan> (gdb) p *node $6 = {type = T_SeqScanState, plan = 0x1b74f58, state = 0x1b78f48, ExecProcNode = 0x714d59 <ExecSeqScan>, ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x1b7a9c0, ps_ExprContext = 0x1b7a5a8, ps_ProjInfo = 0x1b7aa80, scandesc = 0x7f07174f5308}
回到最上層的ExecInitNode,initPlan為NULL
(gdb) ExecInitNode (node=0x1b74f58, estate=0x1b78f48, eflags=16) at execProcnode.c:379 379 subps = NIL; (gdb) 380 foreach(l, node->initPlan) (gdb) p *node $7 = {type = T_SeqScan, startup_cost = 0, total_cost = 1726, plan_rows = 100000, plan_width = 16, parallel_aware = false, parallel_safe = true, plan_node_id = 5, targetlist = 0x1b74e20, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}
完成調(diào)用
(gdb) n 389 result->initPlan = subps; (gdb) 392 if (estate->es_instrument) (gdb) 395 return result; (gdb) 396 }
下面重點(diǎn)考察ExecInitSeqScan和ExecInitHashJoin,首先是ExecInitHashJoin
ExecInitHashJoin->
(gdb) b ExecInitSeqScan Breakpoint 3 at 0x714daf: file nodeSeqscan.c, line 148. (gdb) b ExecInitHashJoin Breakpoint 4 at 0x701f60: file nodeHashjoin.c, line 604. (gdb) c Continuing. Breakpoint 4, ExecInitHashJoin (node=0x1b737c0, estate=0x1b78f48, eflags=16) at nodeHashjoin.c:604 warning: Source file is more recent than executable. 604 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
ExecInitHashJoin->校驗(yàn)并初始化
604 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); (gdb) n 609 hjstate = makeNode(HashJoinState); (gdb) 610 hjstate->js.ps.plan = (Plan *) node; (gdb) 611 hjstate->js.ps.state = estate; (gdb) 618 hjstate->js.ps.ExecProcNode = ExecHashJoin; (gdb) 619 hjstate->js.jointype = node->join.jointype; (gdb) 626 ExecAssignExprContext(estate, &hjstate->js.ps);
ExecInitHashJoin->初步的數(shù)據(jù)結(jié)構(gòu)體
(gdb) p *hjstate $8 = {js = {ps = {type = T_HashJoinState, plan = 0x1b737c0, state = 0x1b78f48, ExecProcNode = 0x701efa <ExecHashJoin>, ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x0}, jointype = JOIN_INNER, single_match = false, joinqual = 0x0}, hashclauses = 0x0, hj_OuterHashKeys = 0x0, hj_InnerHashKeys = 0x0, hj_HashOperators = 0x0, hj_HashTable = 0x0, hj_CurHashValue = 0, hj_CurBucketNo = 0, hj_CurSkewBucketNo = 0, hj_CurTuple = 0x0, hj_OuterTupleSlot = 0x0, hj_HashTupleSlot = 0x0, hj_NullOuterTupleSlot = 0x0, hj_NullInnerTupleSlot = 0x0, hj_FirstOuterTupleSlot = 0x0, hj_JoinState = 0, hj_MatchedOuter = false, hj_OuterNotEmpty = false}
ExecInitHashJoin->獲取HashJoin的outer&inner(PG視為Hash節(jié)點(diǎn))
outerNode為HashJoin,innerNode為Hash
(gdb) n 635 outerNode = outerPlan(node); gdb) n 636 hashNode = (Hash *) innerPlan(node); (gdb) 638 outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags); (gdb) p *node $9 = {join = {plan = {type = T_HashJoin, startup_cost = 3754, total_cost = 8689.6112499999999, plan_rows = 100000, plan_width = 47, parallel_aware = false, parallel_safe = true, plan_node_id = 1, targetlist = 0x1b74cc8, qual = 0x0, lefttree = 0x1b73320, righttree = 0x1b73728, initPlan = 0x0, extParam = 0x0, allParam = 0x0}, jointype = JOIN_INNER, inner_unique = true, joinqual = 0x0}, hashclauses = 0x1b74bb8} (gdb) p *outerNode $12 = {type = T_HashJoin, startup_cost = 3465, total_cost = 8138, plan_rows = 100000, plan_width = 31, parallel_aware = false, parallel_safe = true, plan_node_id = 2, targetlist = 0x1b75588, qual = 0x0, lefttree = 0x1b72da0, righttree = 0x1b73288, initPlan = 0x0, extParam = 0x0, allParam = 0x0} (gdb) p *hashNode $11 = {plan = {type = T_Hash, startup_cost = 164, total_cost = 164, plan_rows = 10000, plan_width = 20, parallel_aware = false, parallel_safe = true, plan_node_id = 6, targetlist = 0x1b75c08, qual = 0x0, lefttree = 0x1b73570, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}, skewTable = 16742, skewColumn = 1, skewInherit = false, rows_total = 0}
ExecInitHashJoin->進(jìn)入outerNode的HashJoin,直接跳過(guò)
(gdb) n Breakpoint 4, ExecInitHashJoin (node=0x1b73320, estate=0x1b78f48, eflags=16) at nodeHashjoin.c:604 604 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); (gdb) finish Run till exit from #0 ExecInitHashJoin (node=0x1b73320, estate=0x1b78f48, eflags=16) at nodeHashjoin.c:604
ExecInitHashJoin->進(jìn)入innerNode的調(diào)用(ExecInitSeqScan)
Breakpoint 3, ExecInitSeqScan (node=0x1b72da0, estate=0x1b78f48, eflags=16) at nodeSeqscan.c:148 warning: Source file is more recent than executable. 148 Assert(outerPlan(node) == NULL); (gdb)
ExecInitSeqScan
ExecInitSeqScan->執(zhí)行校驗(yàn),并創(chuàng)建Node.
注意:ExecProcNode=ExecSeqScan
148 Assert(outerPlan(node) == NULL); (gdb) n 149 Assert(innerPlan(node) == NULL); (gdb) 154 scanstate = makeNode(SeqScanState); (gdb) 155 scanstate->ss.ps.plan = (Plan *) node; (gdb) 156 scanstate->ss.ps.state = estate; (gdb) 157 scanstate->ss.ps.ExecProcNode = ExecSeqScan; (gdb) 164 ExecAssignExprContext(estate, &scanstate->ss.ps); (gdb) p *scanstate $1 = {ss = {ps = {type = T_SeqScanState, plan = 0x1b72da0, state = 0x1b78f48, ExecProcNode = 0x714d59 <ExecSeqScan>, ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x0}, ss_currentRelation = 0x0, ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x0}, pscan_len = 0}
ExecInitSeqScan->打開(kāi)Relation
gdb) n 173 ExecOpenScanRelation(estate, (gdb) 172 scanstate->ss.ss_currentRelation = (gdb) 179 RelationGetDescr(scanstate->ss.ss_currentRelation)); (gdb) p *scanstate->ss.ss_currentRelation $3 = {rd_node = {spcNode = 1663, dbNode = 16402, relNode = 16747}, rd_smgr = 0x1b64650, rd_refcnt = 1, rd_backend = -1, rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true, rd_indexvalid = 1 '\001', rd_statvalid = true, rd_createSubid = 0, rd_newRelfilenodeSubid = 0, rd_rel = 0x7f07174f5c78, rd_att = 0x7f07174f5d90, rd_id = 16747, rd_lockInfo = {lockRelId = {relId = 16747, dbId = 16402}}, rd_rules = 0x0, rd_rulescxt = 0x0, trigdesc = 0x0, rd_rsdesc = 0x0, rd_fkeylist = 0x0, rd_fkeyvalid = false, rd_partkeycxt = 0x0, rd_partkey = 0x0, rd_pdcxt = 0x0, rd_partdesc = 0x0, rd_partcheck = 0x0, rd_indexlist = 0x7f0717447328, rd_oidindex = 0, rd_pkindex = 0, rd_replidindex = 0, rd_statlist = 0x0, rd_indexattr = 0x0, rd_projindexattr = 0x0, rd_keyattr = 0x0, rd_pkattr = 0x0, rd_idattr = 0x0, rd_projidx = 0x0, rd_pubactions = 0x0, rd_options = 0x0, rd_index = 0x0, rd_indextuple = 0x0, rd_amhandler = 0, rd_indexcxt = 0x0, rd_amroutine = 0x0, rd_opfamily = 0x0, rd_opcintype = 0x0, rd_support = 0x0, rd_supportinfo = 0x0, rd_indoption = 0x0, rd_indexprs = 0x0, rd_indpred = 0x0, rd_exclops = 0x0, rd_exclprocs = 0x0, rd_exclstrats = 0x0, rd_amcache = 0x0, rd_indcollation = 0x0, rd_fdwroutine = 0x0, rd_toastoid = 0, pgstat_info = 0x1b0b6c0}
ExecInitSeqScan->使用合適的rowtype打開(kāi)slot(初始化ScanTupleSlot)
(gdb) 178 ExecInitScanTupleSlot(estate, &scanstate->ss, (gdb) 184 ExecInitResultTupleSlotTL(estate, &scanstate->ss.ps); (gdb) p *scanstate->ss.ss_ScanTupleSlot $4 = {type = T_TupleTableSlot, tts_isempty = true, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x7f07174f5d90, tts_mcxt = 0x1b78e30, tts_buffer = 0, tts_nvalid = 0, tts_values = 0x1b79a98, tts_isnull = 0x1b79ab0, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = { bi_hi = 0, bi_lo = 0}, ip_posid = 0}, t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true} (gdb)
ExecInitSeqScan->初始化結(jié)果類型和投影
(gdb) n 185 ExecAssignScanProjectionInfo(&scanstate->ss); (gdb) 191 ExecInitQual(node->plan.qual, (PlanState *) scanstate); (gdb) p *scanstate $5 = {ss = {ps = {type = T_SeqScanState, plan = 0x1b72da0, state = 0x1b78f48, ExecProcNode = 0x714d59 <ExecSeqScan>, ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x1b79d48, ps_ExprContext = 0x1b79978, ps_ProjInfo = 0x1b79e08, scandesc = 0x7f07174f5d90}, ss_currentRelation = 0x7f07174f5a60, ss_currentScanDesc = 0x0, ss_ScanTupleSlot = 0x1b79a38}, pscan_len = 0} (gdb) p *scanstate->ss.ps.ps_ResultTupleSlot $6 = {type = T_TupleTableSlot, tts_isempty = true, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x1b79b30, tts_mcxt = 0x1b78e30, tts_buffer = 0, tts_nvalid = 0, tts_values = 0x1b79da8, tts_isnull = 0x1b79dc0, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = { bi_hi = 0, bi_lo = 0}, ip_posid = 0}, t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true} (gdb) p *scanstate->ss.ps.ps_ProjInfo $7 = {type = T_ProjectionInfo, pi_state = {tag = {type = T_ExprState}, flags = 6 '\006', resnull = false, resvalue = 0, resultslot = 0x1b79d48, steps = 0x1b79ea0, evalfunc = 0x6d104b <ExecInterpExprStillValid>, expr = 0x1b72c68, evalfunc_private = 0x6cec02 <ExecInterpExpr>, steps_len = 5, steps_alloc = 16, parent = 0x1b79860, ext_params = 0x0, innermost_caseval = 0x0, innermost_casenull = 0x0, innermost_domainval = 0x0, innermost_domainnull = 0x0}, pi_exprContext = 0x1b79978}
ExecInitSeqScan->初始化子條件表達(dá)式(為NULL),返回結(jié)果
(gdb) n 190 scanstate->ss.ps.qual = (gdb) 193 return scanstate; (gdb) p *scanstate->ss.ps.qual Cannot access memory at address 0x0
ExecInitSeqScan->回到ExecInitNode for Node SeqScan
(gdb) n 194 } (gdb) ExecInitNode (node=0x1b72da0, estate=0x1b78f48, eflags=16) at execProcnode.c:209 warning: Source file is more recent than executable. 209 break;
ExecInitSeqScan->回到ExecInitNode,結(jié)束調(diào)用
(gdb) n 379 subps = NIL; (gdb) 380 foreach(l, node->initPlan) (gdb) 389 result->initPlan = subps; (gdb) 392 if (estate->es_instrument) (gdb) 395 return result; (gdb) 396 } (gdb)
ExecInitSeqScan->回到ExecInitHashJoin
(gdb) ExecInitHashJoin (node=0x1b73320, estate=0x1b78f48, eflags=16) at nodeHashjoin.c:639 639 outerDesc = ExecGetResultType(outerPlanState(hjstate));
ExecInitHashJoin
ExecInitHashJoin->完成outer relation的處理,開(kāi)始處理inner relation(遞歸調(diào)用ExecInitNode)
639 outerDesc = ExecGetResultType(outerPlanState(hjstate)); (gdb) n 640 innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags); (gdb) Breakpoint 2, ExecInitSeqScan (node=0x1b72ff0, estate=0x1b78f48, eflags=16) at nodeSeqscan.c:148 148 Assert(outerPlan(node) == NULL); (gdb) del 2 (gdb) finish Run till exit from #0 ExecInitSeqScan (node=0x1b72ff0, estate=0x1b78f48, eflags=16) at nodeSeqscan.c:148 0x00000000006e3cd2 in ExecInitNode (node=0x1b72ff0, estate=0x1b78f48, eflags=16) at execProcnode.c:207 207 result = (PlanState *) ExecInitSeqScan((SeqScan *) node, Value returned is $10 = (SeqScanState *) 0x1b7a490 (gdb) ... (gdb) n 641 innerDesc = ExecGetResultType(innerPlanState(hjstate));
ExecInitHashJoin->查看outerDesc和innerDesc
(gdb) p *outerDesc $14 = {natts = 3, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x1b79b50} (gdb) p *innerDesc $15 = {natts = 3, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x1b7ab38} (gdb)
ExecInitHashJoin->初始化節(jié)點(diǎn)slot/類型/投影/元組表等
(gdb) n 647 ExecAssignProjectionInfo(&hjstate->js.ps, NULL); (gdb) 652 hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate, outerDesc); (gdb) 657 hjstate->js.single_match = (node->join.inner_unique || (gdb) 658 node->join.jointype == JOIN_SEMI); (gdb) p *hjstate $16 = {js = {ps = {type = T_HashJoinState, plan = 0x1b73320, state = 0x1b78f48, ExecProcNode = 0x701efa <ExecHashJoin>, ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x1b79860, righttree = 0x1b7a2b8, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x1b7ad30, ps_ExprContext = 0x1b797a0, ps_ProjInfo = 0x1b85bf8, scandesc = 0x0}, jointype = JOIN_INNER, single_match = false, joinqual = 0x0}, hashclauses = 0x0, hj_OuterHashKeys = 0x0, hj_InnerHashKeys = 0x0, hj_HashOperators = 0x0, hj_HashTable = 0x0, hj_CurHashValue = 0, hj_CurBucketNo = 0, hj_CurSkewBucketNo = 0, hj_CurTuple = 0x0, hj_OuterTupleSlot = 0x1b860a8, hj_HashTupleSlot = 0x0, hj_NullOuterTupleSlot = 0x0, hj_NullInnerTupleSlot = 0x0, hj_FirstOuterTupleSlot = 0x0, hj_JoinState = 0, hj_MatchedOuter = false, hj_OuterNotEmpty = false} (gdb) p *hjstate->js.ps.ps_ResultTupleSlot #結(jié)果TupleSlot $20 = {type = T_TupleTableSlot, tts_isempty = true, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x1b857b8, tts_mcxt = 0x1b78e30, tts_buffer = 0, tts_nvalid = 0, tts_values = 0x1b7ad90, tts_isnull = 0x1b7adb8, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = { bi_hi = 0, bi_lo = 0}, ip_posid = 0}, t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true} (gdb) p *hjstate->js.ps.ps_ProjInfo #投影 $18 = {type = T_ProjectionInfo, pi_state = {tag = {type = T_ExprState}, flags = 6 '\006', resnull = false, resvalue = 0, resultslot = 0x1b7ad30, steps = 0x1b85c90, evalfunc = 0x6d104b <ExecInterpExprStillValid>, expr = 0x1b75588, evalfunc_private = 0x6cec02 <ExecInterpExpr>, steps_len = 8, steps_alloc = 16, parent = 0x1b79588, ext_params = 0x0, innermost_caseval = 0x0, innermost_casenull = 0x0, innermost_domainval = 0x0, innermost_domainnull = 0x0}, pi_exprContext = 0x1b797a0} (gdb) p *hjstate->hj_OuterTupleSlot #元組slot $19 = {type = T_TupleTableSlot, tts_isempty = true, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x1b79b30, tts_mcxt = 0x1b78e30, tts_buffer = 0, tts_nvalid = 0, tts_values = 0x1b86108, tts_isnull = 0x1b86120, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = { bi_hi = 0, bi_lo = 0}, ip_posid = 0}, t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true} (gdb) n 657 hjstate->js.single_match = (node->join.inner_unique || (gdb) 661 switch (node->join.jointype) (gdb) p hjstate->js.single_match $21 = false
ExecInitHashJoin->配置外連接的NULL元組(不需要)
(gdb) n 665 break;
ExecInitHashJoin->獲取Hash操作的State,注意ExecProcNode是一個(gè)包裝器(ExecProcNodeFirst),實(shí)際的函數(shù)是ExecHash
(gdb) 694 HashState *hashstate = (HashState *) innerPlanState(hjstate); (gdb) 695 TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot; (gdb) n 697 hjstate->hj_HashTupleSlot = slot; (gdb) (gdb) p *hashstate $22 = {ps = {type = T_HashState, plan = 0x1b73288, state = 0x1b78f48, ExecProcNode = 0x6e41bb <ExecProcNodeFirst>, ExecProcNodeReal = 0x6fb5f2 <ExecHash>, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x1b7a490, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x1b856f8, ps_ExprContext = 0x1b7a3d0, ps_ProjInfo = 0x0, scandesc = 0x0}, hashtable = 0x0, hashkeys = 0x0, shared_info = 0x0, hinstrument = 0x0, parallel_state = 0x0}
ExecInitHashJoin->初始化(子)表達(dá)式,均為NULL
(gdb) n 697 hjstate->hj_HashTupleSlot = slot; (gdb) 704 ExecInitQual(node->join.plan.qual, (PlanState *) hjstate); (gdb) n 703 hjstate->js.ps.qual = (gdb) 706 ExecInitQual(node->join.joinqual, (PlanState *) hjstate); (gdb) 705 hjstate->js.joinqual = (gdb) 708 ExecInitQual(node->hashclauses, (PlanState *) hjstate); (gdb) 707 hjstate->hashclauses = (gdb) 713 hjstate->hj_HashTable = NULL; (gdb) 714 hjstate->hj_FirstOuterTupleSlot = NULL; (gdb) 716 hjstate->hj_CurHashValue = 0; (gdb) 717 hjstate->hj_CurBucketNo = 0; (gdb) 718 hjstate->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO; (gdb) 719 hjstate->hj_CurTuple = NULL; (gdb) 727 lclauses = NIL; (gdb) p *hjstate->js.ps.qual Cannot access memory at address 0x0 (gdb) p *hjstate->js.joinqual Cannot access memory at address 0x0 (gdb)
ExecInitHashJoin->將哈希子句解構(gòu)為外部和內(nèi)部參數(shù)值,以便能夠分別計(jì)算這些子表達(dá)式;還可以列出哈希運(yùn)算符oid,以便查找要使用的哈希函數(shù).
... (gdb) p *hjstate->hj_OuterHashKeys $25 = {type = T_List, length = 1, head = 0x1b86f98, tail = 0x1b86f98} (gdb) p *hjstate->hj_InnerHashKeys $26 = {type = T_List, length = 1, head = 0x1b87708, tail = 0x1b87708} (gdb) p *hjstate->hj_HashOperators $27 = {type = T_OidList, length = 1, head = 0x1b87768, tail = 0x1b87768} (gdb)
ExecInitHashJoin->完成調(diào)用
(gdb) n 746 hjstate->hj_JoinState = HJ_BUILD_HASHTABLE; (gdb) 747 hjstate->hj_MatchedOuter = false; (gdb) 748 hjstate->hj_OuterNotEmpty = false; (gdb) 750 return hjstate; (gdb) 751 }
ExecInitHashJoin->最終結(jié)果(注意:這是最上層的HashJoin)
(gdb) p *hjstate $28 = {js = {ps = {type = T_HashJoinState, plan = 0x1b73320, state = 0x1b78f48, ExecProcNode = 0x701efa <ExecHashJoin>, ExecProcNodeReal = 0x0, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x1b79860, righttree = 0x1b7a2b8, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x1b7ad30, ps_ExprContext = 0x1b797a0, ps_ProjInfo = 0x1b85bf8, scandesc = 0x0}, jointype = JOIN_INNER, single_match = false, joinqual = 0x0}, hashclauses = 0x1b86168, hj_OuterHashKeys = 0x1b86fc0, hj_InnerHashKeys = 0x1b87730, hj_HashOperators = 0x1b87790, hj_HashTable = 0x0, hj_CurHashValue = 0, hj_CurBucketNo = 0, hj_CurSkewBucketNo = -1, hj_CurTuple = 0x0, hj_OuterTupleSlot = 0x1b860a8, hj_HashTupleSlot = 0x1b856f8, hj_NullOuterTupleSlot = 0x0, hj_NullInnerTupleSlot = 0x0, hj_FirstOuterTupleSlot = 0x0, hj_JoinState = 1, hj_MatchedOuter = false, hj_OuterNotEmpty = false}
到此,關(guān)于“PostgreSQL中什么函數(shù)通過(guò)遞歸調(diào)用初始化計(jì)劃樹(shù)中的所有Plan節(jié)點(diǎn)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
免責(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)容。