您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“PostgreSQL源碼中NOT IN的作用是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“PostgreSQL源碼中NOT IN的作用是什么”吧!
SubPlanState
子計(jì)劃運(yùn)行期狀態(tài)
/* ---------------- * SubPlanState node * ---------------- */ typedef struct SubPlanState { NodeTag type; SubPlan *subplan; /* expression plan node */ struct PlanState *planstate; /* subselect plan's state tree */ struct PlanState *parent; /* parent plan node's state tree */ ExprState *testexpr; /* 組合表達(dá)式狀態(tài);state of combining expression */ List *args; /* 參數(shù)表達(dá)式狀態(tài);states of argument expression(s) */ HeapTuple curTuple; /* subplan最近的元組;copy of most recent tuple from subplan */ Datum curArray; /* most recent array from ARRAY() subplan */ /* these are used when hashing the subselect's output: */ TupleDesc descRight; /* 投影后的子查詢描述符;subselect desc after projection */ ProjectionInfo *projLeft; /* for projecting lefthand exprs */ ProjectionInfo *projRight; /* for projecting subselect output */ TupleHashTable hashtable; /* hash table for no-nulls subselect rows */ TupleHashTable hashnulls; /* hash table for rows with null(s) */ bool havehashrows; /* true if hashtable is not empty */ bool havenullrows; /* true if hashnulls is not empty */ MemoryContext hashtablecxt; /* memory context containing hash tables */ MemoryContext hashtempcxt; /* temp memory context for hash tables */ ExprContext *innerecontext; /* econtext for computing inner tuples */ AttrNumber *keyColIdx; /* control data for hash tables */ Oid *tab_eq_funcoids; /* equality func oids for table * datatype(s) */ Oid *tab_collations; /* collations for hash and comparison */ FmgrInfo *tab_hash_funcs; /* hash functions for table datatype(s) */ FmgrInfo *tab_eq_funcs; /* equality functions for table datatype(s) */ FmgrInfo *lhs_hash_funcs; /* hash functions for lefthand datatype(s) */ FmgrInfo *cur_eq_funcs; /* equality functions for LHS vs. table */ ExprState *cur_eq_comp; /* equality comparator for LHS vs. table */ } SubPlanState;
SubPlan
子查詢計(jì)劃
/* * SubPlan - executable expression node for a subplan (sub-SELECT) * * The planner replaces SubLink nodes in expression trees with SubPlan * nodes after it has finished planning the subquery. SubPlan references * a sub-plantree stored in the subplans list of the toplevel PlannedStmt. * (We avoid a direct link to make it easier to copy expression trees * without causing multiple processing of the subplan.) * 查詢規(guī)劃器在完成子查詢的規(guī)劃后使用SubPlan節(jié)點(diǎn)替換表達(dá)式樹(shù)中的SubLink節(jié)點(diǎn)。 * SubPlan引用了存儲(chǔ)在高層PlannedStmt中的subplans鏈表中的sub-plantree。 * (避免使用直接鏈接,從而使得拷貝表達(dá)式樹(shù)相對(duì)比較簡(jiǎn)單) * * In an ordinary subplan, testexpr points to an executable expression * (OpExpr, an AND/OR tree of OpExprs, or RowCompareExpr) for the combining * operator(s); the left-hand arguments are the original lefthand expressions, * and the right-hand arguments are PARAM_EXEC Param nodes representing the * outputs of the sub-select. (NOTE: runtime coercion functions may be * inserted as well.) This is just the same expression tree as testexpr in * the original SubLink node, but the PARAM_SUBLINK nodes are replaced by * suitably numbered PARAM_EXEC nodes. * 常規(guī)情況下,testexpr指向用于組合操作的可執(zhí)行表達(dá)式(OpExpr、OpExprs的AND/OR樹(shù)或者RowCompareExpr); * 左參數(shù)是原始的左表達(dá)式,右參數(shù)是PARAM_EXEC參數(shù)節(jié)點(diǎn)用以表示子查詢的輸出。 * 與原始SubLink節(jié)點(diǎn)的testexpr具有相同的表達(dá)式樹(shù),但PARAM_SUBLINK節(jié)點(diǎn)則使用合適的已編號(hào)PARAM_EXEC節(jié)點(diǎn)替代。 * * If the sub-select becomes an initplan rather than a subplan, the executable * expression is part of the outer plan's expression tree (and the SubPlan * node itself is not, but rather is found in the outer plan's initPlan * list). In this case testexpr is NULL to avoid duplication. * 如果子查詢成了initplan而不是subplan,可執(zhí)行的表達(dá)式是外層plan表達(dá)式樹(shù)的一部分。 * 這種情況下,testexpr為NULL以避免重復(fù)。 * * The planner also derives lists of the values that need to be passed into * and out of the subplan. Input values are represented as a list "args" of * expressions to be evaluated in the outer-query context (currently these * args are always just Vars, but in principle they could be any expression). * The values are assigned to the global PARAM_EXEC params indexed by parParam * (the parParam and args lists must have the same ordering). setParam is a * list of the PARAM_EXEC params that are computed by the sub-select, if it * is an initplan; they are listed in order by sub-select output column * position. (parParam and setParam are integer Lists, not Bitmapsets, * because their ordering is significant.) * 規(guī)劃器還派生了需要傳入和傳出子計(jì)劃的值的鏈表。 * 輸入值標(biāo)識(shí)位表達(dá)式的“args”鏈表,在外層查詢上下文中進(jìn)行解析。 * (這些args通常是Vars,但原則上它們可以是任意表達(dá)式) * 這些值以parParam為索引給全局PARAM_EXEC參數(shù)賦值。 * setParam是PARAM_EXEC參數(shù)鏈表,通過(guò)子查詢(如為initplan)計(jì)算所得。 * 它們按子查詢輸出列的位置進(jìn)行排序組織為鏈表形式。 * (parParam和setParam是整型鏈表,而不是Bitmapsets鏈表) * * Also, the planner computes startup and per-call costs for use of the * SubPlan. Note that these include the cost of the subquery proper, * evaluation of the testexpr if any, and any hashtable management overhead. * 同時(shí),規(guī)劃器計(jì)算SubPlan啟動(dòng)和每次調(diào)用的成本。注意:包括子查詢正常解析testexpr的成本以及哈希表管理成本。 */ typedef struct SubPlan { Expr xpr;//表達(dá)式 /* Fields copied from original SubLink: */ //從SubLink中拷貝而來(lái) SubLinkType subLinkType; /* see above */ /* The combining operators, transformed to an executable expression: */ //組合操作符,轉(zhuǎn)換為可執(zhí)行的表達(dá)式 Node *testexpr; /* OpExpr or RowCompareExpr expression tree */ List *paramIds; /* 參數(shù)IDs;IDs of Params embedded in the above */ /* Identification of the Plan tree to use: */ //Plan tree標(biāo)識(shí) int plan_id; /* Index (from 1) in PlannedStmt.subplans */ /* Identification of the SubPlan for EXPLAIN and debugging purposes: */ //EXPLAIN和debug目的的SubPlan標(biāo)識(shí) char *plan_name; /* A name assigned during planning */ /* Extra data useful for determining subplan's output type: */ //用于確定subplan輸出類型的額外信息 Oid firstColType; /* subplan結(jié)果的第一個(gè)列類型;Type of first column of subplan result */ int32 firstColTypmod; /* 第一列的Typmod;Typmod of first column of subplan result */ Oid firstColCollation; /* 第一列的Collation;Collation of first column of subplan * result */ /* Information about execution strategy: */ //執(zhí)行階段的相關(guān)信息 bool useHashTable; /* 是否使用哈希表存儲(chǔ)子查詢輸出;true to store subselect output in a hash * table (implies we are doing "IN") */ bool unknownEqFalse; /* 如OK為T,如為未知?jiǎng)t為F;快速處理null值;true if it's okay to return FALSE when the * spec result is UNKNOWN; this allows much * simpler handling of null values */ bool parallel_safe; /* 是否并行安全?is the subplan parallel-safe? */ /* Note: parallel_safe does not consider contents of testexpr or args */ /* Information for passing params into and out of the subselect: */ //用于給子查詢傳入和傳出參數(shù)的信息 /* setParam and parParam are lists of integers (param IDs) */ //setParam和parParam是整型鏈表(param IDs) List *setParam; /* initplan subqueries have to set these * Params for parent plan */ List *parParam; /* indices of input Params from parent plan */ List *args; /* 以parParam值進(jìn)行傳遞的表達(dá)式;exprs to pass as parParam values */ /* Estimated execution costs: */ //估算執(zhí)行成本 Cost startup_cost; /* one-time setup cost */ Cost per_call_cost; /* cost for each subplan evaluation */ } SubPlan;
SubLinkType
SubLink類型
/* * SubLink * * A SubLink represents a subselect appearing in an expression, and in some * cases also the combining operator(s) just above it. The subLinkType * indicates the form of the expression represented: * EXISTS_SUBLINK EXISTS(SELECT ...) * ALL_SUBLINK (lefthand) op ALL (SELECT ...) * ANY_SUBLINK (lefthand) op ANY (SELECT ...) * ROWCOMPARE_SUBLINK (lefthand) op (SELECT ...) * EXPR_SUBLINK (SELECT with single targetlist item ...) * MULTIEXPR_SUBLINK (SELECT with multiple targetlist items ...) * ARRAY_SUBLINK ARRAY(SELECT with single targetlist item ...) * CTE_SUBLINK WITH query (never actually part of an expression) * For ALL, ANY, and ROWCOMPARE, the lefthand is a list of expressions of the * same length as the subselect's targetlist. ROWCOMPARE will *always* have * a list with more than one entry; if the subselect has just one target * then the parser will create an EXPR_SUBLINK instead (and any operator * above the subselect will be represented separately). * ROWCOMPARE, EXPR, and MULTIEXPR require the subselect to deliver at most * one row (if it returns no rows, the result is NULL). * ALL, ANY, and ROWCOMPARE require the combining operators to deliver boolean * results. ALL and ANY combine the per-row results using AND and OR * semantics respectively. * ARRAY requires just one target column, and creates an array of the target * column's type using any number of rows resulting from the subselect. * * SubLink is classed as an Expr node, but it is not actually executable; * it must be replaced in the expression tree by a SubPlan node during * planning. * * NOTE: in the raw output of gram.y, testexpr contains just the raw form * of the lefthand expression (if any), and operName is the String name of * the combining operator. Also, subselect is a raw parsetree. During parse * analysis, the parser transforms testexpr into a complete boolean expression * that compares the lefthand value(s) to PARAM_SUBLINK nodes representing the * output columns of the subselect. And subselect is transformed to a Query. * This is the representation seen in saved rules and in the rewriter. * * In EXISTS, EXPR, MULTIEXPR, and ARRAY SubLinks, testexpr and operName * are unused and are always null. * * subLinkId is currently used only for MULTIEXPR SubLinks, and is zero in * other SubLinks. This number identifies different multiple-assignment * subqueries within an UPDATE statement's SET list. It is unique only * within a particular targetlist. The output column(s) of the MULTIEXPR * are referenced by PARAM_MULTIEXPR Params appearing elsewhere in the tlist. * * The CTE_SUBLINK case never occurs in actual SubLink nodes, but it is used * in SubPlans generated for WITH subqueries. */ typedef enum SubLinkType { EXISTS_SUBLINK, ALL_SUBLINK, ANY_SUBLINK, ROWCOMPARE_SUBLINK, EXPR_SUBLINK, MULTIEXPR_SUBLINK, ARRAY_SUBLINK, CTE_SUBLINK /* for SubPlans only */ } SubLinkType;
SubLink
SubLink結(jié)構(gòu)體
typedef struct SubLink { Expr xpr; SubLinkType subLinkType; /* see above */ int subLinkId; /* ID (1..n); 0 if not MULTIEXPR */ Node *testexpr; /* outer-query test for ALL/ANY/ROWCOMPARE */ List *operName; /* originally specified operator name */ Node *subselect; /* subselect as Query* or raw parsetree */ int location; /* token location, or -1 if unknown */ } SubLink;
ExecScanSubPlan
/* * ExecScanSubPlan: default case where we have to rescan subplan each time * 默認(rèn)情況下每次都不得不重新掃描subplan */ static Datum ExecScanSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull) { SubPlan *subplan = node->subplan;//子計(jì)劃 PlanState *planstate = node->planstate;//計(jì)劃運(yùn)行期狀態(tài) SubLinkType subLinkType = subplan->subLinkType;//子鏈接類型 MemoryContext oldcontext;//原內(nèi)存上下文 TupleTableSlot *slot;//元組slot Datum result;//結(jié)果指針 bool found = false; /* 如找到至少一個(gè)元組,則返回T;true if got at least one subplan tuple */ ListCell *pvar;//臨時(shí)變量 ListCell *l;//臨時(shí)變量 ArrayBuildStateAny *astate = NULL;// /* * MULTIEXPR subplans, when "executed", just return NULL; but first we * mark the subplan's output parameters as needing recalculation. (This * is a bit of a hack: it relies on the subplan appearing later in its * targetlist than any of the referencing Params, so that all the Params * have been evaluated before we re-mark them for the next evaluation * cycle. But in general resjunk tlist items appear after non-resjunk * ones, so this should be safe.) Unlike ExecReScanSetParamPlan, we do * *not* set bits in the parent plan node's chgParam, because we don't * want to cause a rescan of the parent. * * MULTIEXPR處理邏輯 */ if (subLinkType == MULTIEXPR_SUBLINK) { EState *estate = node->parent->state; foreach(l, subplan->setParam) { int paramid = lfirst_int(l); ParamExecData *prm = &(estate->es_param_exec_vals[paramid]); prm->execPlan = node; } *isNull = true; return (Datum) 0; } /* Initialize ArrayBuildStateAny in caller's context, if needed */ //數(shù)組 if (subLinkType == ARRAY_SUBLINK) astate = initArrayResultAny(subplan->firstColType, CurrentMemoryContext, true); /* * We are probably in a short-lived expression-evaluation context. Switch * to the per-query context for manipulating the child plan's chgParam, * calling ExecProcNode on it, etc. */ //切換上下文 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); /* * Set Params of this plan from parent plan correlation values. (Any * calculation we have to do is done in the parent econtext, since the * Param values don't need to have per-query lifetime.) */ //通過(guò)父計(jì)劃相關(guān)值中設(shè)置子計(jì)劃參數(shù) Assert(list_length(subplan->parParam) == list_length(node->args)); forboth(l, subplan->parParam, pvar, node->args) { int paramid = lfirst_int(l); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar), econtext, &(prm->isnull)); planstate->chgParam = bms_add_member(planstate->chgParam, paramid); } /* * Now that we've set up its parameters, we can reset the subplan. */ //執(zhí)行ReScan //Reset a plan node so that its output can be re-scanned. ExecReScan(planstate); /* * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result * is boolean as are the results of the combining operators. We combine * results across tuples (if the subplan produces more than one) using OR * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK. * (ROWCOMPARE_SUBLINK doesn't allow multiple tuples from the subplan.) * NULL results from the combining operators are handled according to the * usual SQL semantics for OR and AND. The result for no input tuples is * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for * ROWCOMPARE_SUBLINK. * 除EXPR_SUBLINK和ARRAY_SUBLINK外的所有sublink,結(jié)果是布爾值(組合運(yùn)算符的結(jié)果). * PG通過(guò)跨元組(如子計(jì)劃產(chǎn)生多個(gè)元組)合并結(jié)果,對(duì)于ANY_SUBLINK使用OR語(yǔ)義,ALL_SUBLINK則使用AND語(yǔ)義. * (ROWCOMPARE_SUBLINK不允許子計(jì)劃返回多個(gè)元組) * 從組合操作符中返回的NULL遵循SQL中的OR和AND語(yǔ)義. * 如沒(méi)有輸入元組,ANY_SUBLINK為FALSE,ALL_SUBLINK為TRUE,ROWCOMPARE_SUBLINK為NULL. * * For EXPR_SUBLINK we require the subplan to produce no more than one * tuple, else an error is raised. If zero tuples are produced, we return * NULL. Assuming we get a tuple, we just use its first column (there can * be only one non-junk column in this case). * 對(duì)于EXPR_SUBLINK,需要subplan產(chǎn)生不超過(guò)一個(gè)元組,否則報(bào)錯(cuò).如果沒(méi)有元組產(chǎn)生,返回NULL. * 假定獲取到一個(gè)元組,則使用第一個(gè)列(這種情況下只有一個(gè)non-junk列). * * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples, * and form an array of the first column's values. Note in particular * that we produce a zero-element array if no tuples are produced (this is * a change from pre-8.3 behavior of returning NULL). * 對(duì)于ARRAY_SUBLINK,允許subplan產(chǎn)生任意數(shù)目的元組,使用第一個(gè)列值組成數(shù)組. * 特別注意的是如沒(méi)有元組產(chǎn)生則產(chǎn)生0個(gè)元素的數(shù)組(8.3以前是返回NULL). */ result = BoolGetDatum(subLinkType == ALL_SUBLINK);//ALL為T,否則為F *isNull = false; for (slot = ExecProcNode(planstate); !TupIsNull(slot); slot = ExecProcNode(planstate))//循環(huán)獲取元組,直至沒(méi)有元組為NULL(即已完成) { //元組描述符 TupleDesc tdesc = slot->tts_tupleDescriptor; Datum rowresult;//結(jié)果 bool rownull;//是否為空? int col;//列計(jì)數(shù)器 ListCell *plst;//臨時(shí)變量 if (subLinkType == EXISTS_SUBLINK)//EXISTS { found = true; result = BoolGetDatum(true); break; } if (subLinkType == EXPR_SUBLINK)//EXPR表達(dá)式 { /* cannot allow multiple input tuples for EXPR sublink */ if (found) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), errmsg("more than one row returned by a subquery used as an expression"))); found = true; /* * We need to copy the subplan's tuple in case the result is of * pass-by-ref type --- our return value will point into this * copied tuple! Can't use the subplan's instance of the tuple * since it won't still be valid after next ExecProcNode() call. * node->curTuple keeps track of the copied tuple for eventual * freeing. */ if (node->curTuple) heap_freetuple(node->curTuple); node->curTuple = ExecCopySlotHeapTuple(slot); result = heap_getattr(node->curTuple, 1, tdesc, isNull); /* keep scanning subplan to make sure there's only one tuple */ continue; } if (subLinkType == ARRAY_SUBLINK)//數(shù)組 { Datum dvalue; bool disnull; found = true; /* stash away current value */ Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid); dvalue = slot_getattr(slot, 1, &disnull); astate = accumArrayResultAny(astate, dvalue, disnull, subplan->firstColType, oldcontext); /* keep scanning subplan to collect all values */ continue; } /* cannot allow multiple input tuples for ROWCOMPARE sublink either */ if (subLinkType == ROWCOMPARE_SUBLINK && found)//行比較 ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), errmsg("more than one row returned by a subquery used as an expression"))); found = true;//初始為T /* * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params * representing the columns of the sub-select, and then evaluate the * combining expression. * 對(duì)于ALL,ANY和ROWCOMPARE子鏈接,加載表示子查詢列的Params,并解析組合表達(dá)式 */ col = 1;//列從1計(jì)數(shù) foreach(plst, subplan->paramIds)//循環(huán)遍歷子查詢參數(shù) { int paramid = lfirst_int(plst); ParamExecData *prmdata; prmdata = &(econtext->ecxt_param_exec_vals[paramid]); Assert(prmdata->execPlan == NULL); //獲取參數(shù)值 prmdata->value = slot_getattr(slot, col, &(prmdata->isnull)); //下一個(gè)列 col++; } //解析表達(dá)式 rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext, &rownull); if (subLinkType == ANY_SUBLINK) { //ANY : 使用OR語(yǔ)義組合 /* combine across rows per OR semantics */ if (rownull) *isNull = true; else if (DatumGetBool(rowresult)) { result = BoolGetDatum(true); *isNull = false; break; /* needn't look at any more rows */ } } else if (subLinkType == ALL_SUBLINK) { //ALL : 使用AND語(yǔ)義 /* combine across rows per AND semantics */ if (rownull) *isNull = true; else if (!DatumGetBool(rowresult)) { result = BoolGetDatum(false); *isNull = false; break; /* needn't look at any more rows */ } } else { /* must be ROWCOMPARE_SUBLINK */ //這里一定是ROWCOMPARE result = rowresult; *isNull = rownull; } } MemoryContextSwitchTo(oldcontext); if (subLinkType == ARRAY_SUBLINK) { /* We return the result in the caller's context */ //在調(diào)用者上下文中返回結(jié)果 result = makeArrayResultAny(astate, oldcontext, true); } else if (!found) { /* * deal with empty subplan result. result/isNull were previously * initialized correctly for all sublink types except EXPR and * ROWCOMPARE; for those, return NULL. * subplan沒(méi)有結(jié)果返回,設(shè)置result&isNull值 */ if (subLinkType == EXPR_SUBLINK || subLinkType == ROWCOMPARE_SUBLINK) { result = (Datum) 0; *isNull = true; } } //返回結(jié)果 return result; }
ExecProcNode
執(zhí)行輸入?yún)?shù)node的ExecProcNode方法。
/* ---------------------------------------------------------------- * ExecProcNode * * Execute the given node to return a(nother) tuple. * ---------------------------------------------------------------- */ #ifndef FRONTEND static inline TupleTableSlot * ExecProcNode(PlanState *node) { if (node->chgParam != NULL) /* something changed? */ ExecReScan(node); /* let ReScan handle this */ return node->ExecProcNode(node); } #endif
執(zhí)行SQL:
[pg12@localhost ~]$ psql -d testdb Timing is on. Expanded display is used automatically. psql (12.0) Type "help" for help. [local]:5432 pg12@testdb=# [local]:5432 pg12@testdb=# select * from tbl; id | value ----+------- 1 | 2 (1 row) Time: 2.678 ms [local]:5432 pg12@testdb=# select count(*) from t_big_null; count ---------- 10000001 (1 row) Time: 679.972 ms [local]:5432 pg12@testdb=# analyze tbl; ANALYZE Time: 64.442 ms [local]:5432 pg12@testdb=# analyze t_big_null; ANALYZE Time: 434.702 ms [local]:5432 pg12@testdb=# [local]:5432 pg12@testdb=# select pg_backend_pid(); pg_backend_pid ---------------- 18758 (1 row) Time: 1.990 ms [local]:5432 pg12@testdb=# select * from tbl a where a.id not in (select b.id from t_big_null b);
啟動(dòng)gdb跟蹤
(gdb) b ExecScanSubPlan Breakpoint 1 at 0x73014b: file nodeSubplan.c, line 228. (gdb) c Continuing. Breakpoint 1, ExecScanSubPlan (node=0x1c89158, econtext=0x1c88990, isNull=0x1c88cad) at nodeSubplan.c:228 228 SubPlan *subplan = node->subplan; (gdb) (gdb) n 229 PlanState *planstate = node->planstate; (gdb) 230 SubLinkType subLinkType = subplan->subLinkType; (gdb) 234 bool found = false; /* true if got at least one subplan tuple */
subplan變量值(結(jié)構(gòu)體SubPlan)
其中testexpr是測(cè)試表達(dá)式,操作符是整型的等值比較,
左操作符是Var,數(shù)據(jù)表的第一個(gè)列,類型為23-int4(select * from pg_type where oid=23;)
有操作符是Param,執(zhí)行期設(shè)置,對(duì)應(yīng)參數(shù)索引編號(hào)為0,類型為23-int4
paramIds是鏈表,第一項(xiàng)ID值為0(int_value = 0)
子查詢結(jié)果的第一個(gè)列類型為23-int4
(gdb) p *subplan $1 = {xpr = {type = T_SubPlan}, subLinkType = ANY_SUBLINK, testexpr = 0x1cb8790, paramIds = 0x1cb8758, plan_id = 1, plan_name = 0x1cb8a80 "SubPlan 1", firstColType = 23, firstColTypmod = -1, firstColCollation = 0, useHashTable = false, unknownEqFalse = false, parallel_safe = true, setParam = 0x0, parParam = 0x0, args = 0x0, startup_cost = 0, per_call_cost = 129155.31875000001} (gdb) p *subplan->testexpr $2 = {type = T_OpExpr} (gdb) p *(OpExpr *)subplan->testexpr $3 = {xpr = {type = T_OpExpr}, opno = 96, opfuncid = 65, opresulttype = 16, opretset = false, opcollid = 0, inputcollid = 0, args = 0x1cb8868, location = 31} (gdb) set $expr=(OpExpr *)subplan->testexpr (gdb) p *$expr->args $4 = {type = T_List, length = 2, head = 0x1cb8840, tail = 0x1cb88d8} (gdb) p *$expr->args->head $5 = {data = {ptr_value = 0x1cb87e8, int_value = 30115816, oid_value = 30115816}, next = 0x1cb88d8} (gdb) p *(Node *)$expr->args->head->data.ptr_value $6 = {type = T_Var} (gdb) p *(Var *)$expr->args->head->data.ptr_value $7 = {xpr = {type = T_Var}, varno = 1, varattno = 1, vartype = 23, vartypmod = -1, varcollid = 0, varlevelsup = 0, varnoold = 1, varoattno = 1, location = 26} (gdb) p *(Var *)$expr->args->head->next->data.ptr_value $8 = {xpr = {type = T_Param}, varno = 1, varattno = 0, vartype = 23, vartypmod = -1, varcollid = 0, varlevelsup = 4294967295, varnoold = 2139062142, varoattno = 16, location = 0} (gdb) p *(Param *)$expr->args->head->next->data.ptr_value $9 = {xpr = {type = T_Param}, paramkind = PARAM_EXEC, paramid = 0, paramtype = 23, paramtypmod = -1, paramcollid = 0, location = -1} (gdb) ### [local]:5432 pg12@testdb=# select * from pg_proc where oid = 65; --> opfuncid = 65,函數(shù) -[ RECORD 1 ]---+------- oid | 65 proname | int4eq pronamespace | 11 proowner | 10 prolang | 12 procost | 1 prorows | 0 provariadic | 0 prosupport | - prokind | f prosecdef | f proleakproof | t proisstrict | t proretset | f provolatile | i proparallel | s pronargs | 2 pronargdefaults | 0 prorettype | 16 proargtypes | 23 23 proallargtypes | proargmodes | proargnames | proargdefaults | protrftypes | prosrc | int4eq probin | proconfig | proacl | Time: 6.253 ms ### (gdb) p *subplan->paramIds $11 = {type = T_IntList, length = 1, head = 0x1cb8730, tail = 0x1cb8730} (gdb) p *subplan->paramIds->head $12 = {data = {ptr_value = 0x7f7f7f7f00000000, int_value = 0, oid_value = 0}, next = 0x0} (gdb)
planstate變量值,實(shí)際的執(zhí)行節(jié)點(diǎn)是ExecMaterial
(gdb) p *planstate $15 = {type = T_MaterialState, plan = 0x1cb8900, state = 0x1c87da8, ExecProcNode = 0x6f802a <ExecProcNodeFirst>, ExecProcNodeReal = 0x720ecf <ExecMaterial>, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x1c88160, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleDesc = 0x1c88580, ps_ResultTupleSlot = 0x1c88698, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x1c88468, scanops = 0xc3e720 <TTSOpsMinimalTuple>, outerops = 0x0, innerops = 0x0, resultops = 0xc3e720 <TTSOpsMinimalTuple>, scanopsfixed = true, outeropsfixed = false, inneropsfixed = false, resultopsfixed = true, scanopsset = true, outeropsset = false, inneropsset = false, resultopsset = true} (gdb)
subLinkType變量,類型為ANY_SUBLINK,把NOT IN轉(zhuǎn)為ANY_SUBLINK
(gdb) p subLinkType $16 = ANY_SUBLINK
設(shè)置變量,執(zhí)行相關(guān)檢查等
(gdb) n 237 ArrayBuildStateAny *astate = NULL; (gdb) 250 if (subLinkType == MULTIEXPR_SUBLINK) (gdb) 266 if (subLinkType == ARRAY_SUBLINK) (gdb) 275 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); (gdb) 282 Assert(list_length(subplan->parParam) == list_length(node->args)); (gdb) 284 forboth(l, subplan->parParam, pvar, node->args) (gdb) p subplan->parParam $17 = (List *) 0x0
執(zhí)行ExecReScan,planstate->ExecProcNode實(shí)際為ExecMaterial
(gdb) n 298 ExecReScan(planstate); (gdb) p *planstate $20 = {type = T_MaterialState, plan = 0x1cb8900, state = 0x1c87da8, ExecProcNode = 0x720ecf <ExecMaterial>, ExecProcNodeReal = 0x720ecf <ExecMaterial>, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x1c88160, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleDesc = 0x1c88580, ps_ResultTupleSlot = 0x1c88698, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x1c88468, scanops = 0xc3e720 <TTSOpsMinimalTuple>, outerops = 0x0, innerops = 0x0, resultops = 0xc3e720 <TTSOpsMinimalTuple>, scanopsfixed = true, outeropsfixed = false, inneropsfixed = false, resultopsfixed = true, scanopsset = true, outeropsset = false, inneropsset = false, resultopsset = true} (gdb)
初始化result&isNull變量
(gdb) n 321 result = BoolGetDatum(subLinkType == ALL_SUBLINK); (gdb) 322 *isNull = false; (gdb) p result $18 = 0
執(zhí)行循環(huán),slot從planstate->ExecProcNode(即ExecMaterial)中獲取
(gdb) n 324 for (slot = ExecProcNode(planstate); (gdb) 325 !TupIsNull(slot); (gdb) (gdb) p *slot $22 = {type = T_TupleTableSlot, tts_flags = 20, tts_nvalid = 0, tts_ops = 0xc3e720 <TTSOpsMinimalTuple>, tts_tupleDescriptor = 0x1c88580, tts_values = 0x1c88708, tts_isnull = 0x1c88710, tts_mcxt = 0x1c87c90, tts_tid = { ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, tts_tableOid = 0} (gdb) p slot->tts_values[0] $23 = 0 (gdb)
獲取slot的描述符
(gdb) 328 TupleDesc tdesc = slot->tts_tupleDescriptor; (gdb) p tdesc $21 = (TupleDesc) 0x206e6f6900000000
判斷subLink類型執(zhí)行相關(guān)邏輯,循環(huán)paramIds,填充參數(shù)值
(gdb) n 334 if (subLinkType == EXISTS_SUBLINK) (gdb) 341 if (subLinkType == EXPR_SUBLINK) (gdb) 367 if (subLinkType == ARRAY_SUBLINK) (gdb) 383 if (subLinkType == ROWCOMPARE_SUBLINK && found) (gdb) 388 found = true; (gdb) 395 col = 1; (gdb) 396 foreach(plst, subplan->paramIds) (gdb) p *slot $22 = {type = T_TupleTableSlot, tts_flags = 20, tts_nvalid = 0, tts_ops = 0xc3e720 <TTSOpsMinimalTuple>, tts_tupleDescriptor = 0x1c88580, tts_values = 0x1c88708, tts_isnull = 0x1c88710, tts_mcxt = 0x1c87c90, tts_tid = { ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, tts_tableOid = 0} (gdb) p *slot->tts_values[0] Cannot access memory at address 0x0 (gdb) p slot->tts_values[0] $23 = 0 (gdb) n 398 int paramid = lfirst_int(plst); (gdb) 401 prmdata = &(econtext->ecxt_param_exec_vals[paramid]); (gdb) p paramid $24 = 0 (gdb) n 402 Assert(prmdata->execPlan == NULL); (gdb) p *prmdata $25 = {execPlan = 0x0, value = 0, isnull = false} (gdb) n 403 prmdata->value = slot_getattr(slot, col, &(prmdata->isnull)); (gdb) n 404 col++; (gdb) p *prmdata $26 = {execPlan = 0x0, value = 2, isnull = false} (gdb) n 396 foreach(plst, subplan->paramIds) (gdb)
解析表達(dá)式,亦即解析表達(dá)式tbl.id = 2,獲取結(jié)果
(gdb) 407 rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext, (gdb) p *(Var *)$expr->args->head->data.ptr_value $28 = {xpr = {type = T_Var}, varno = 1, varattno = 1, vartype = 23, vartypmod = -1, varcollid = 0, varlevelsup = 0, varnoold = 1, varoattno = 1, location = 26} (gdb) p *(Param *)$expr->args->head->next->data.ptr_value $29 = {xpr = {type = T_Param}, paramkind = PARAM_EXEC, paramid = 0, paramtype = 23, paramtypmod = -1, paramcollid = 0, location = -1} (gdb) p econtext->ecxt_param_exec_vals[0] $30 = {execPlan = 0x0, value = 2, isnull = false}
由于tbl.id = 1,因此表達(dá)式解析結(jié)果為F
(gdb) n 410 if (subLinkType == ANY_SUBLINK) (gdb) p rowresult $31 = 0 (gdb)
判斷subLink類型,如為ANY則進(jìn)入相應(yīng)邏輯
(gdb) n 410 if (subLinkType == ANY_SUBLINK) (gdb) p rowresult $31 = 0 (gdb) n 413 if (rownull) (gdb) p rownull $32 = false (gdb) n 415 else if (DatumGetBool(rowresult)) (gdb)
結(jié)果不為T,因此再次循環(huán)執(zhí)行,獲取slot,這次的值應(yīng)為3,因?yàn)? <> 1,因此再次循環(huán)直至t_big_null中出現(xiàn)值1或完成掃描
326 slot = ExecProcNode(planstate)) (gdb) ... (gdb) 403 prmdata->value = slot_getattr(slot, col, &(prmdata->isnull)); (gdb) 404 col++; (gdb) p prmdata->value $36 = 3 (gdb) p slot->tts_values[0] $37 = 3 (gdb) ...
完成執(zhí)行
(gdb) c Continuing. ### [local]:5432 pg12@testdb=# select * from tbl a where a.id not in (select b.id from t_big_null b); id | value ----+------- (0 rows) Time: 3089703.031 ms (51:29.703) [local]:5432 pg12@testdb=# [local]:5432 pg12@testdb=# ###
調(diào)用棧
Breakpoint 1, ExecScanSubPlan (node=0x1c89158, econtext=0x1c88990, isNull=0x1c88cad) at nodeSubplan.c:228 228 SubPlan *subplan = node->subplan; (gdb) bt #0 ExecScanSubPlan (node=0x1c89158, econtext=0x1c88990, isNull=0x1c88cad) at nodeSubplan.c:228 #1 0x000000000072fe5e in ExecSubPlan (node=0x1c89158, econtext=0x1c88990, isNull=0x1c88cad) at nodeSubplan.c:90 #2 0x00000000006e90a8 in ExecEvalSubPlan (state=0x1c88ca8, op=0x1c88d80, econtext=0x1c88990) at execExprInterp.c:3783 #3 0x00000000006e48b2 in ExecInterpExpr (state=0x1c88ca8, econtext=0x1c88990, isnull=0x7fff7b9514f7) at execExprInterp.c:1484 #4 0x00000000006e50b8 in ExecInterpExprStillValid (state=0x1c88ca8, econtext=0x1c88990, isNull=0x7fff7b9514f7) at execExprInterp.c:1769 #5 0x00000000006f9ec0 in ExecEvalExprSwitchContext (state=0x1c88ca8, econtext=0x1c88990, isNull=0x7fff7b9514f7) at ../../../src/include/executor/executor.h:307 #6 0x00000000006f9fb8 in ExecQual (state=0x1c88ca8, econtext=0x1c88990) at ../../../src/include/executor/executor.h:376 #7 0x00000000006fa37d in ExecScan (node=0x1c88878, accessMtd=0x72b84c <SeqNext>, recheckMtd=0x72b8f1 <SeqRecheck>) at execScan.c:228 #8 0x000000000072b93b in ExecSeqScan (pstate=0x1c88878) at nodeSeqscan.c:112 #9 0x00000000006f8077 in ExecProcNodeFirst (node=0x1c88878) at execProcnode.c:445 #10 0x00000000006ed3cd in ExecProcNode (node=0x1c88878) at ../../../src/include/executor/executor.h:239 #11 0x00000000006efbb3 in ExecutePlan (estate=0x1c87da8, planstate=0x1c88878, use_parallel_mode=false, operation=CMD_SELECT, sendTuples=true, numberTuples=0, direction=ForwardScanDirection, dest=0x1cbc7c0, execute_once=true) at execMain.c:1646 #12 0x00000000006ed9df in standard_ExecutorRun (queryDesc=0x1be78b8, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:364 #13 0x00000000006ed815 in ExecutorRun (queryDesc=0x1be78b8, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:308 #14 0x00000000008f1010 in PortalRunSelect (portal=0x1c27d78, forward=true, count=0, dest=0x1cbc7c0) at pquery.c:929 #15 0x00000000008f0cae in PortalRun (portal=0x1c27d78, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x1cbc7c0, altdest=0x1cbc7c0, completionTag=0x7fff7b951890 "") at pquery.c:770 #16 0x00000000008ead35 in exec_simple_query ( query_string=0x1bc1d88 "select * from tbl a where a.id not in (select b.id from t_big_null b);") at postgres.c:1215 #17 0x00000000008eefa5 in PostgresMain (argc=1, argv=0x1bedf18, dbname=0x1bedd60 "testdb", username=0x1bbeaa8 "pg12") at postgres.c:4236 #18 0x0000000000845915 in BackendRun (port=0x1be3d30) at postmaster.c:4431 #19 0x00000000008450f3 in BackendStartup (port=0x1be3d30) at postmaster.c:4122 #20 0x000000000084132f in ServerLoop () at postmaster.c:1704 #21 0x0000000000840be5 in PostmasterMain (argc=1, argv=0x1bbca60) at postmaster.c:1377 #22 0x0000000000761469 in main (argc=1, argv=0x1bbca60) at main.c:228 (gdb)
到此,相信大家對(duì)“PostgreSQL源碼中NOT IN的作用是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jì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)容。