博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PostgreSQL在何处处理 sql查询之五十九
阅读量:5889 次
发布时间:2019-06-19

本文共 7616 字,大约阅读时间需要 25 分钟。

由于用单纯的SQL语句来探查代码,看得还是不够清楚。

所以我再采用如下的方法:

postgres=# explain select dept.no_emps,emp.age from dept,emp where emp.name = dept.mgr and dept.dept_name = 'shoe';                            QUERY PLAN                            ------------------------------------------------------------------ Hash Join  (cost=19.30..45.07 rows=23 width=8)   Hash Cond: ((emp.name)::text = (dept.mgr)::text)   ->  Seq Scan on emp  (cost=0.00..21.30 rows=1130 width=42)   ->  Hash  (cost=19.25..19.25 rows=4 width=42)         ->  Seq Scan on dept  (cost=0.00..19.25 rows=4 width=42)               Filter: ((dept_name)::text = 'shoe'::text)(6 rows)postgres=#

通过对代码的跟踪,可以看到 ExecInitNode被执行了四次。

每次都运行时的 NodeTag依次是:

124--T_HashJoin

109--T_SeqScan

131--T_Hash

109--T_SeqScan

正好和用 explain看到的顺序相同。

下面要进一步看代码中相关的结构如何变化。

看这段源代码:

/* ---------------------------------------------------------------- *        ExecInitHashJoin * *        Init routine for HashJoin node. * ---------------------------------------------------------------- */HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags){    HashJoinState *hjstate;    Plan       *outerNode;    Hash       *hashNode;    List       *lclauses;    List       *rclauses;    List       *hoperators;    ListCell   *l;    /* check for unsupported flags */    Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));    /*     * create state structure     */    hjstate = makeNode(HashJoinState);    hjstate->js.ps.plan = (Plan *) node;    hjstate->js.ps.state = estate;    /*     * Miscellaneous initialization     *     * create expression context for node     */    ExecAssignExprContext(estate, &hjstate->js.ps);    /*     * initialize child expressions     */    hjstate->js.ps.targetlist = (List *)        ExecInitExpr((Expr *) node->join.plan.targetlist,                     (PlanState *) hjstate);    hjstate->js.ps.qual = (List *)        ExecInitExpr((Expr *) node->join.plan.qual,                     (PlanState *) hjstate);    hjstate->js.jointype = node->join.jointype;    hjstate->js.joinqual = (List *)        ExecInitExpr((Expr *) node->join.joinqual,                     (PlanState *) hjstate);    hjstate->hashclauses = (List *)        ExecInitExpr((Expr *) node->hashclauses,                     (PlanState *) hjstate);    /*     * initialize child nodes     *     * 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.     */    outerNode = outerPlan(node);    hashNode = (Hash *) innerPlan(node);    outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags);    innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags);    /*     * tuple table initialization     */    ExecInitResultTupleSlot(estate, &hjstate->js.ps);    hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);    /* set up null tuples for outer joins, if needed */    switch (node->join.jointype)    {        case JOIN_INNER:        case JOIN_SEMI:            break;        case JOIN_LEFT:        case JOIN_ANTI:            hjstate->hj_NullInnerTupleSlot =                ExecInitNullTupleSlot(estate,                                 ExecGetResultType(innerPlanState(hjstate)));            break;        case JOIN_RIGHT:            hjstate->hj_NullOuterTupleSlot =                ExecInitNullTupleSlot(estate,                                 ExecGetResultType(outerPlanState(hjstate)));            break;        case JOIN_FULL:            hjstate->hj_NullOuterTupleSlot =                ExecInitNullTupleSlot(estate,                                 ExecGetResultType(outerPlanState(hjstate)));            hjstate->hj_NullInnerTupleSlot =                ExecInitNullTupleSlot(estate,                                 ExecGetResultType(innerPlanState(hjstate)));            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     */    {        HashState  *hashstate = (HashState *) innerPlanState(hjstate);        TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot;        hjstate->hj_HashTupleSlot = slot;    }    /*     * initialize tuple type and projection info     */    ExecAssignResultTypeFromTL(&hjstate->js.ps);    ExecAssignProjectionInfo(&hjstate->js.ps, NULL);    ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,                          ExecGetResultType(outerPlanState(hjstate)));    /*     * initialize hash-specific info     */    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.     */    lclauses = NIL;    rclauses = NIL;    hoperators = NIL;    foreach(l, hjstate->hashclauses)    {        FuncExprState *fstate = (FuncExprState *) lfirst(l);        OpExpr       *hclause;        Assert(IsA(fstate, FuncExprState));        hclause = (OpExpr *) fstate->xprstate.expr;        Assert(IsA(hclause, OpExpr));        lclauses = lappend(lclauses, linitial(fstate->args));        rclauses = lappend(rclauses, lsecond(fstate->args));        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 = rclauses;    hjstate->js.ps.ps_TupFromTlist = false;    hjstate->hj_JoinState = HJ_BUILD_HASHTABLE;    hjstate->hj_MatchedOuter = false;    hjstate->hj_OuterNotEmpty = false;    return hjstate;}

将之简化:

/* ---------------------------------------------------------------- *        ExecInitHashJoin * *        Init routine for HashJoin node. * ---------------------------------------------------------------- */HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags){    HashJoinState *hjstate;    Plan       *outerNode;    Hash       *hashNode;    List       *lclauses;    List       *rclauses;    List       *hoperators;    ListCell   *l;    ...    /*     * initialize child nodes     *     * 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.     */    outerNode = outerPlan(node);    hashNode = (Hash *) innerPlan(node);    outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags);    innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags);    ...    return hjstate;}

可以看到其实 

outerNode = outerPlan(node) 就是: outerNode = (((Plan *)(node))->lefttree)

hashNode = (Hash *) innerPlan(node) 就是:hashNode = (((Plan *)(node))->righttree)

outerPlanState(hjstate) 就是 (((PlanState *)(hjstate))->lefttree)

innerPlanState(hjstate就是 (((PlanState *)(hjstate))->righttree)

或者说,在对 Hash 节点进行处理的时候,要分别处理左节点和右节点。

由于计划树结构比较复杂,借鉴explain.c中的代码来观察如何读取其中的数据,是一个可行的办法。

转载地址:http://hvysx.baihongyu.com/

你可能感兴趣的文章
PHP队列的实现
查看>>
单点登录加验证码例子
查看>>
[T-SQL]从变量与数据类型说起
查看>>
稀疏自动编码之反向传播算法(BP)
查看>>
二叉搜索树转换成双向链表
查看>>
WebLogic和Tomcat的区别
查看>>
java类中 获取服务器的IP 端口
查看>>
occActiveX - ActiveX with OpenCASCADE
查看>>
redmine
查看>>
css 序
查看>>
DirectshowLib摄像头拍照的”未找到可用于建立连接的介质筛选器组合“ 解决办法...
查看>>
三种简单排序
查看>>
Dalvik VM和JVM的比较以及Android新的虚拟机ART
查看>>
【CSU 1803】2016
查看>>
SQLServer 批量备份与还原
查看>>
51Nod 1010 只包含因子2 3 5的数 Label:None
查看>>
Java中String和byte[]间的转换浅析
查看>>
什么是异步
查看>>
WordPress 主题切换
查看>>
【java】path和classpath
查看>>