PostgreSQL源码中NOT IN的作用是什么
本篇内容主要讲解“PostgreSQL源码中NOT IN的作用是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL源码中NOT IN的作用是什么”吧!
一、数据结构
SubPlanState
子计划运行期状态
typedef struct SubPlanState
{
NodeTag type;
SubPlan *subplan;
struct PlanState *planstate;
struct PlanState *parent;
ExprState *testexpr;
List *args;
HeapTuple curTuple;
Datum curArray;
TupleDesc descRight;
ProjectionInfo *projLeft;
ProjectionInfo *projRight;
TupleHashTable hashtable;
TupleHashTable hashnulls;
bool havehashrows;
bool havenullrows;
MemoryContext hashtablecxt;
MemoryContext hashtempcxt;
ExprContext *innerecontext;
AttrNumber *keyColIdx;
Oid *tab_eq_funcoids;
Oid *tab_collations;
FmgrInfo *tab_hash_funcs;
FmgrInfo *tab_eq_funcs;
FmgrInfo *lhs_hash_funcs;
FmgrInfo *cur_eq_funcs;
ExprState *cur_eq_comp;
} SubPlanState;
SubPlan
子查询计划
typedef struct SubPlan
{
Expr xpr;//表达式
//从SubLink中拷贝而来
SubLinkType subLinkType;
//组合操作符,转换为可执行的表达式
Node *testexpr;
List *paramIds;
//Plan tree标识
int plan_id;
//EXPLAIN和debug目的的SubPlan标识
char *plan_name;
//用于确定subplan输出类型的额外信息
Oid firstColType;
int32 firstColTypmod;
Oid firstColCollation;
//执行阶段的相关信息
bool useHashTable;
bool unknownEqFalse;
bool parallel_safe;
//用于给子查询传入和传出参数的信息
//setParam和parParam是整型链表(param IDs)
List *setParam;
List *parParam;
List *args;
//估算执行成本
Cost startup_cost;
Cost per_call_cost;
} SubPlan;
SubLinkType
SubLink类型
typedef enum SubLinkType
{
EXISTS_SUBLINK,
ALL_SUBLINK,
ANY_SUBLINK,
ROWCOMPARE_SUBLINK,
EXPR_SUBLINK,
MULTIEXPR_SUBLINK,
ARRAY_SUBLINK,
CTE_SUBLINK
} SubLinkType;
SubLink
SubLink结构体
typedef struct SubLink
{
Expr xpr;
SubLinkType subLinkType;
int subLinkId;
Node *testexpr;
List *operName;
Node *subselect;
int location;
} SubLink;
二、源码解读
ExecScanSubPlan
static Datum
ExecScanSubPlan(SubPlanState *node,
ExprContext *econtext,
bool *isNull)
{
SubPlan *subplan = node->subplan;//子计划
PlanState *planstate = node->planstate;//计划运行期状态
SubLinkType subLinkType = subplan->subLinkType;//子链接类型
MemoryContext oldcontext;//原内存上下文
TupleTableSlot *slot;//元组slot
Datum result;//结果指针
bool found = false;
ListCell *pvar;//临时变量
ListCell *l;//临时变量
ArrayBuildStateAny *astate = NULL;//
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;
}
//数组
if (subLinkType == ARRAY_SUBLINK)
astate = initArrayResultAny(subplan->firstColType,
CurrentMemoryContext, true);
//切换上下文
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
//通过父计划相关值中设置子计划参数
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);
}
//执行ReScan
//Reset a plan node so that its output can be re-scanned.
ExecReScan(planstate);
result = BoolGetDatum(subLinkType == ALL_SUBLINK);//ALL为T,否则为F
*isNull = false;
for (slot = ExecProcNode(planstate);
!TupIsNull(slot);
slot = ExecProcNode(planstate))//循环获取元组,直至没有元组为NULL(即已完成)
{
//元组描述符
TupleDesc tdesc = slot->tts_tupleDescriptor;
Datum rowresult;//结果
bool rownull;//是否为空?
int col;//列计数器
ListCell *plst;//临时变量
if (subLinkType == EXISTS_SUBLINK)//EXISTS
{
found = true;
result = BoolGetDatum(true);
break;
}
if (subLinkType == EXPR_SUBLINK)//EXPR表达式
{
if (found)
ereport(ERROR,
(errcode(ERRCODE_CARDINALITY_VIOLATION),
errmsg("more than one row returned by a subquery used as an expression")));
found = true;
if (node->curTuple)
heap_freetuple(node->curTuple);
node->curTuple = ExecCopySlotHeapTuple(slot);
result = heap_getattr(node->curTuple, 1, tdesc, isNull);
continue;
}
if (subLinkType == ARRAY_SUBLINK)//数组
{
Datum dvalue;
bool disnull;
found = true;
Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
dvalue = slot_getattr(slot, 1, &disnull);
astate = accumArrayResultAny(astate, dvalue, disnull,
subplan->firstColType, oldcontext);
continue;
}
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
col = 1;//列从1计数
foreach(plst, subplan->paramIds)//循环遍历子查询参数
{
int paramid = lfirst_int(plst);
ParamExecData *prmdata;
prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
Assert(prmdata->execPlan == NULL);
//获取参数值
prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
//下一个列
col++;
}
//解析表达式
rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
&rownull);
if (subLinkType == ANY_SUBLINK)
{
//ANY : 使用OR语义组合
if (rownull)
*isNull = true;
else if (DatumGetBool(rowresult))
{
result = BoolGetDatum(true);
*isNull = false;
break;
}
}
else if (subLinkType == ALL_SUBLINK)
{
//ALL : 使用AND语义
if (rownull)
*isNull = true;
else if (!DatumGetBool(rowresult))
{
result = BoolGetDatum(false);
*isNull = false;
break;
}
}
else
{
//这里一定是ROWCOMPARE
result = rowresult;
*isNull = rownull;
}
}
MemoryContextSwitchTo(oldcontext);
if (subLinkType == ARRAY_SUBLINK)
{
//在调用者上下文中返回结果
result = makeArrayResultAny(astate, oldcontext, true);
}
else if (!found)
{
if (subLinkType == EXPR_SUBLINK ||
subLinkType == ROWCOMPARE_SUBLINK)
{
result = (Datum) 0;
*isNull = true;
}
}
//返回结果
return result;
}
ExecProcNode
执行输入参数node的ExecProcNode方法。
#ifndef FRONTEND
static inline TupleTableSlot *
ExecProcNode(PlanState *node)
{
if (node->chgParam != NULL)
ExecReScan(node);
return node->ExecProcNode(node);
}
#endif
三、跟踪分析
执行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);
启动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;
subplan变量值(结构体SubPlan)
其中testexpr是测试表达式,操作符是整型的等值比较,
左操作符是Var,数据表的第一个列,类型为23-int4(select * from pg_type where oid=23;)
有操作符是Param,执行期设置,对应参数索引编号为0,类型为23-int4
paramIds是链表,第一项ID值为0(int_value = 0)
子查询结果的第一个列类型为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,函数
-[ 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 |
proclass="lazy" data-src | 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变量值,实际的执行节点是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转为ANY_SUBLINK
(gdb) p subLinkType
$16 = ANY_SUBLINK
设置变量,执行相关检查等
(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
执行ExecReScan,planstate->ExecProcNode实际为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
执行循环,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类型执行相关逻辑,循环paramIds,填充参数值
(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)
解析表达式,亦即解析表达式tbl.id = 2,获取结果
(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,因此表达式解析结果为F
(gdb) n
410 if (subLinkType == ANY_SUBLINK)
(gdb) p rowresult
$31 = 0
(gdb)
判断subLink类型,如为ANY则进入相应逻辑
(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)
结果不为T,因此再次循环执行,获取slot,这次的值应为3,因为3 <> 1,因此再次循环直至t_big_null中出现值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)
...
完成执行
(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=#
###
调用栈
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 ../../../class="lazy" data-src/include/executor/executor.h:307
#6 0x00000000006f9fb8 in ExecQual (state=0x1c88ca8, econtext=0x1c88990)
at ../../../class="lazy" data-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 ../../../class="lazy" data-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)
到此,相信大家对“PostgreSQL源码中NOT IN的作用是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341