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

本文共 7714 字,大约阅读时间需要 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://www.cnblogs.com/gaojian/archive/2013/06/11/3131778.html,如需转载请自行联系原作者

你可能感兴趣的文章
【100题】第四十五题 雅虎面试两道题(矩阵判断、数组划分)
查看>>
MySQL基础知识
查看>>
HTML页面优化
查看>>
centos6下安装docker
查看>>
常见的算法PHP 版,自整理
查看>>
使用UITableView隐藏的复选功能
查看>>
自定义下拉菜单(按钮下面出现下拉菜单),失去焦点后,如何下拉菜单自动消失,以及弹出窗体位置一直变化问题...
查看>>
uboot指令和环境变量
查看>>
Python之模块(二)
查看>>
Python跳出循环语句continue与break的区别
查看>>
内存中堆,栈的区别
查看>>
JavaScript
查看>>
django 配置邮件发送 send_email
查看>>
程序员聊人生
查看>>
ScrollView中嵌套WebView SrcollView自动向下滚动
查看>>
Python尾递归-创始人为何不愿TRE以及我们如何模拟TRE
查看>>
PKUSC2016
查看>>
Java内存分配和内存管理
查看>>
CNCF 有哪些具体的项目内容?
查看>>
[转]Oracle 清除incident和trace -- ADRCI用法
查看>>