这篇文章主要为大家展示了“APPEND Plan node节点的初始化和执行逻辑”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“APPEND Plan Node节
这篇文章主要为大家展示了“APPEND Plan node节点的初始化和执行逻辑”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“APPEND Plan Node节点的初始化和执行逻辑”这篇文章吧。
AppendState
用于Append Node执行的数据结构
struct AppendState;
typedef struct AppendState AppendState;
struct ParallelAppendState;
typedef struct ParallelAppendState ParallelAppendState;
struct PartitionPruneState;
struct AppendState
{
//第一个字段为NodeTag
PlanState ps;
//PlanStates数组
PlanState **appendplans;
//数组大小
int as_nplans;
//那个计划将要被/正在被执行
int as_whichplan;
//包含第一个部分计划的appendplans数组编号
int as_first_partial_plan;
//并行执行的协调信息
ParallelAppendState *as_pstate;
//协调信息大小
Size pstate_len;
//分区裁剪信息
struct PartitionPruneState *as_prune_state;
//有效的子计划位图集
Bitmapset *as_valid_subplans;
//选择下个子计划的实现函数
bool (*choose_next_subplan) (AppendState *);
};
ExecInitAppend
ExecInitAppend函数为开始append node的所有子关系扫描执行相关的初始化.
AppendState *
ExecInitAppend(Append *node, EState *estate, int eflags)
{
AppendState *appendstate = makeNode(AppendState);
PlanState **appendplanstates;
Bitmapset *validsubplans;
int nplans;
int firstvalid;
int i,
j;
ListCell *lc;
//检查不支持的标记
Assert(!(eflags & EXEC_FLAG_MARK));
appendstate->ps.plan = (Plan *) node;
appendstate->ps.state = estate;
appendstate->ps.ExecProcNode = ExecAppend;
//让choose_next_subplan_* 函数处理第一个子计划的设置
appendstate->as_whichplan = INVALID_SUBPLAN_INDEX;
//如允许运行时分区裁剪,则配置分区裁剪
if (node->part_prune_info != NULL)
{
PartitionPruneState *prunestate;
//需要独立的表达式上下文来解析分区表达式
ExecAssignExprContext(estate, &appendstate->ps);
//为裁剪创建工作数据结构信息
prunestate = ExecCreatePartitionPruneState(&appendstate->ps,
node->part_prune_info);
appendstate->as_prune_state = prunestate;
//如需要,执行初始的分区裁剪
if (prunestate->do_initial_prune)
{
//确定那个子计划在初始裁剪中仍"存活"
validsubplans = ExecFindInitialMatchingSubPlans(prunestate,
list_length(node->appendplans));
if (bms_is_empty(validsubplans))
{
appendstate->as_whichplan = NO_MATCHING_SUBPLANS;
//标记第一个子计划为有效的,以便在接下来可以初始化
validsubplans = bms_make_singleton(0);
}
//子计划数目
nplans = bms_num_members(validsubplans);
}
else
{
//需要初始化所有的的子计划
nplans = list_length(node->appendplans);
Assert(nplans > 0);
validsubplans = bms_add_range(NULL, 0, nplans - 1);
}
if (!prunestate->do_exec_prune)
{
Assert(nplans > 0);
appendstate->as_valid_subplans = bms_add_range(NULL, 0, nplans - 1);
}
}
else
{
//不需要运行期裁剪
nplans = list_length(node->appendplans);
Assert(nplans > 0);
appendstate->as_valid_subplans = validsubplans =
bms_add_range(NULL, 0, nplans - 1);
appendstate->as_prune_state = NULL;
}
ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual);
//从每一个子节点中返回slot,但并不固定
appendstate->ps.resultopsset = true;
appendstate->ps.resultopsfixed = false;
appendplanstates = (PlanState **) palloc(nplans *
sizeof(PlanState *));
j = i = 0;
firstvalid = nplans;
foreach(lc, node->appendplans)
{
if (bms_is_member(i, validsubplans))
{
Plan *initNode = (Plan *) lfirst(lc);
if (i >= node->first_partial_plan && j < firstvalid)
firstvalid = j;
appendplanstates[j++] = ExecInitNode(initNode, estate, eflags);//初始化节点
}
i++;
}
//配置Append State
appendstate->as_first_partial_plan = firstvalid;
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
appendstate->ps.ps_ProjInfo = NULL;
//对于并行查询,该值后面会被覆盖
appendstate->choose_next_subplan = choose_next_subplan_locally;
return appendstate;
}
ExecAppend
ExecAppend在多个子计划中进行迭代处理
static TupleTableSlot *
ExecAppend(PlanState *pstate)
{
AppendState *node = castNode(AppendState, pstate);
if (node->as_whichplan < 0)
{
if (node->as_whichplan == INVALID_SUBPLAN_INDEX &&
!node->choose_next_subplan(node))
return ExecClearTuple(node->ps.ps_ResultTupleSlot);//出错,则清除tuple,返回
//如无匹配的子计划,返回
else if (node->as_whichplan == NO_MATCHING_SUBPLANS)
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
}
for (;;)//循环获取tuple slot
{
PlanState *subnode;
TupleTableSlot *result;
CHECK_FOR_INTERRUPTS();
Assert(node->as_whichplan >= 0 && node->as_whichplan < node->as_nplans);
subnode = node->appendplans[node->as_whichplan];
result = ExecProcNode(subnode);
if (!TupIsNull(result))
{
return result;
}
//选择新的子计划,如无,则完成调用
if (!node->choose_next_subplan(node))
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
}
}
测试脚本如下
testdb=# explain verbose select * from t_hash_partition where c1 = 1 OR c1 = 2;
QUERY PLAN
-------------------------------------------------------------------------------------
Append (cost=0.00..30.53 rows=6 width=200)
-> Seq Scan on public.t_hash_partition_1 (cost=0.00..15.25 rows=3 width=200)
Output: t_hash_partition_1.c1, t_hash_partition_1.c2, t_hash_partition_1.c3
Filter: ((t_hash_partition_1.c1 = 1) OR (t_hash_partition_1.c1 = 2))
-> Seq Scan on public.t_hash_partition_3 (cost=0.00..15.25 rows=3 width=200)
Output: t_hash_partition_3.c1, t_hash_partition_3.c2, t_hash_partition_3.c3
Filter: ((t_hash_partition_3.c1 = 1) OR (t_hash_partition_3.c1 = 2))
(7 rows)
ExecInitAppend
启动gdb,设置断点
(gdb) b ExecInitAppend
Breakpoint 1 at 0x6efa8a: file nodeAppend.c, line 103.
(gdb) c
Continuing.
Breakpoint 1, ExecInitAppend (node=0x27af638, estate=0x27be058, eflags=16) at nodeAppend.c:103
103 AppendState *appendstate = makeNode(AppendState);
初始化AppendState
(gdb) n
113 Assert(!(eflags & EXEC_FLAG_MARK));
(gdb)
119 ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
(gdb)
124 appendstate->ps.plan = (Plan *) node;
(gdb)
125 appendstate->ps.state = estate;
(gdb)
126 appendstate->ps.ExecProcNode = ExecAppend;
(gdb)
129 appendstate->as_whichplan = INVALID_SUBPLAN_INDEX;
(gdb)
不需要运行期分区裁剪
(gdb)
132 if (node->part_prune_info != NULL)
(gdb) p node->part_prune_info
$1 = (struct PartitionPruneInfo *) 0x0
(gdb)
需要初始化所有的的子计划
(gdb) n
190 nplans = list_length(node->appendplans);
(gdb)
196 Assert(nplans > 0);
(gdb)
198 bms_add_range(NULL, 0, nplans - 1);
(gdb)
197 appendstate->as_valid_subplans = validsubplans =
(gdb) n
199 appendstate->as_prune_state = NULL;
(gdb) p *validsubplans
$4 = {nWords = 1, words = 0x27be38c}
(gdb) p *validsubplans->words
$5 = 3 --> 即No.0 + No.1
(gdb)
初始化结果元组类型和slot
(gdb) n
205 ExecInitResultTupleSlotTL(estate, &appendstate->ps);
(gdb)
207 appendplanstates = (PlanState **) palloc(nplans *
(gdb)
在每一个有效的计划上执行ExecInitNode,同时保持结果到appendplanstates数组中.
(gdb)
216 j = i = 0;
(gdb) n
217 firstvalid = nplans;
(gdb)
218 foreach(lc, node->appendplans)
(gdb) p nplans
$6 = 2
(gdb) p node->appendplans
$7 = (List *) 0x27b30f0
(gdb) p *node->appendplans
$8 = {type = T_List, length = 2, head = 0x27b30c8, tail = 0x27b33D8}
(gdb)
遍历appendplans,初始化appendplans中的节点(SeqScan)
(gdb) n
220 if (bms_is_member(i, validsubplans))
(gdb) n
222 Plan *initNode = (Plan *) lfirst(lc);
(gdb)
228 if (i >= node->first_partial_plan && j < firstvalid)
(gdb)
231 appendplanstates[j++] = ExecInitNode(initNode, estate, eflags);
(gdb) p j
$9 = 0
(gdb) p i
$10 = 0
(gdb) n
233 i++;
(gdb)
218 foreach(lc, node->appendplans)
(gdb)
220 if (bms_is_member(i, validsubplans))
(gdb)
222 Plan *initNode = (Plan *) lfirst(lc);
(gdb)
228 if (i >= node->first_partial_plan && j < firstvalid)
(gdb) p *initNode
$11 = {type = T_SeqScan, startup_cost = 0, total_cost = 15.25, plan_rows = 3, plan_width = 200, parallel_aware = false,
parallel_safe = true, plan_node_id = 2, targetlist = 0x27b31a8, qual = 0x27b3308, lefttree = 0x0, righttree = 0x0,
initPlan = 0x0, extParam = 0x0, allParam = 0x0}
(gdb) n
231 appendplanstates[j++] = ExecInitNode(initNode, estate, eflags);
(gdb)
233 i++;
(gdb)
218 foreach(lc, node->appendplans)
(gdb)
236 appendstate->as_first_partial_plan = firstvalid;
(gdb)
完成初始化,其中choose_next_subplan函数为choose_next_subplan_locally函数
(gdb) p firstvalid
$12 = 2
(gdb) n
237 appendstate->appendplans = appendplanstates;
(gdb)
238 appendstate->as_nplans = nplans;
(gdb)
244 appendstate->ps.ps_ProjInfo = NULL;
(gdb)
247 appendstate->choose_next_subplan = choose_next_subplan_locally;
(gdb)
249 return appendstate;
(gdb) p choose_next_subplan_locally
$13 = {_Bool (AppendState *)} 0x6f02d8 <choose_next_subplan_locally>
(gdb) p *appendstate
$15 = {ps = {type = T_AppendState, plan = 0x27af638, state = 0x27be058, ExecProcNode = 0x6efe19 <ExecAppend>,
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 = 0x27be5c0,
ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x0}, appendplans = 0x27be6b8, as_nplans = 2, as_whichplan = -1,
as_first_partial_plan = 2, as_pstate = 0x0, pstate_len = 0, as_prune_state = 0x0, as_valid_subplans = 0x27be388,
choose_next_subplan = 0x6f02d8 <choose_next_subplan_locally>}
ExecAppend
设置断点,进入ExecAppend
(gdb) del
Delete all breakpoints? (y or n) y
(gdb) b ExecAppend
Breakpoint 2 at 0x6efe2a: file nodeAppend.c, line 261.
(gdb) c
Continuing.
Breakpoint 2, ExecAppend (pstate=0x27be270) at nodeAppend.c:261
261 AppendState *node = castNode(AppendState, pstate);
输入参数为先前已完成初始化的AppendState
(gdb) p *(AppendState *)pstate
$19 = {ps = {type = T_AppendState, plan = 0x27af638, state = 0x27be058, ExecProcNode = 0x6efe19 <ExecAppend>,
ExecProcNodeReal = 0x6efe19 <ExecAppend>, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0,
qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0,
ps_ResultTupleSlot = 0x27be5c0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, scandesc = 0x0}, appendplans = 0x27be6b8,
as_nplans = 2, as_whichplan = -1, as_first_partial_plan = 2, as_pstate = 0x0, pstate_len = 0, as_prune_state = 0x0,
as_valid_subplans = 0x27be388, choose_next_subplan = 0x6f02d8 <choose_next_subplan_locally>}
如果没有子计划选中,必须在开始前选择一个(选择子计划:No.0)
(gdb) n
263 if (node->as_whichplan < 0)
(gdb)
269 if (node->as_whichplan == INVALID_SUBPLAN_INDEX &&
(gdb)
270 !node->choose_next_subplan(node))
(gdb)
269 if (node->as_whichplan == INVALID_SUBPLAN_INDEX &&
(gdb)
274 else if (node->as_whichplan == NO_MATCHING_SUBPLANS)
(gdb) p node->as_whichplan
$20 = 0
(gdb) n
283 CHECK_FOR_INTERRUPTS();
获取子计划并执行
(gdb)
288 Assert(node->as_whichplan >= 0 && node->as_whichplan < node->as_nplans);
(gdb)
289 subnode = node->appendplans[node->as_whichplan];
(gdb)
294 result = ExecProcNode(subnode);
(gdb) p *subnode
$21 = {type = T_SeqScanState, plan = 0x27b2728, state = 0x27be058, ExecProcNode = 0x6e4bde <ExecProcNodeFirst>,
ExecProcNodeReal = 0x71578d <ExecSeqScan>, instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0,
qual = 0x27bec88, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0,
ps_ResultTupleSlot = 0x27bebc8, ps_ExprContext = 0x27be7f8, ps_ProjInfo = 0x0, scandesc = 0x7f7d049417e0}
返回slot
(gdb) n
296 if (!TupIsNull(result))
(gdb) p *result
$22 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false,
tts_tuple = 0x27c5500, tts_tupleDescriptor = 0x7f7d049417e0, tts_mcxt = 0x27bdf40, tts_buffer = 120, tts_nvalid = 1,
tts_values = 0x27be950, tts_isnull = 0x27be968, 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 = 4, tts_fixedTupleDescriptor = true}
如第一个子计划执行完毕,则选择下一个子计划(调用choose_next_subplan函数切换到下一个子计划)
(gdb) c
Continuing.
Breakpoint 2, ExecAppend (pstate=0x27be270) at nodeAppend.c:261
261 AppendState *node = castNode(AppendState, pstate);
(gdb) n
263 if (node->as_whichplan < 0)
(gdb)
283 CHECK_FOR_INTERRUPTS();
(gdb)
288 Assert(node->as_whichplan >= 0 && node->as_whichplan < node->as_nplans);
(gdb)
289 subnode = node->appendplans[node->as_whichplan];
(gdb)
294 result = ExecProcNode(subnode);
(gdb)
296 if (!TupIsNull(result))
(gdb)
307 if (!node->choose_next_subplan(node))
(gdb)
309 }
以上是“APPEND Plan Node节点的初始化和执行逻辑”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网数据库频道!
--结束END--
本文标题: APPEND Plan Node节点的初始化和执行逻辑
本文链接: https://www.lsjlt.com/news/64076.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-05-16
2024-05-16
2024-05-16
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0