• PostgreSQL在何处处理 sql查询之四十九


    接前面,继续对 subquery_planner来分析:

    下面这一段都是对 表达式进行处理的,对我的简单查询,可以忽略。

        /*
         * Do expression preprocessing on targetlist and quals, as well as other
         * random expressions in the querytree.  Note that we do not need to
         * handle sort/group expressions explicitly, because they are actually
         * part of the targetlist.
         */
        parse->targetList = (List *)
            preprocess_expression(root, (Node *) parse->targetList,
                                  EXPRKIND_TARGET);
    
        parse->returningList = (List *)
            preprocess_expression(root, (Node *) parse->returningList,
                                  EXPRKIND_TARGET);
    
        preprocess_qual_conditions(root, (Node *) parse->jointree);
    
        parse->havingQual = preprocess_expression(root, parse->havingQual,
                                                  EXPRKIND_QUAL);
    
        foreach(l, parse->windowClause)
        {
            WindowClause *wc = (WindowClause *) lfirst(l);
    
            /* partitionClause/orderClause are sort/group expressions */
            wc->startOffset = preprocess_expression(root, wc->startOffset,
                                                    EXPRKIND_LIMIT);
            wc->endOffset = preprocess_expression(root, wc->endOffset,
                                                  EXPRKIND_LIMIT);
        }
    
        parse->limitOffset = preprocess_expression(root, parse->limitOffset,
                                                   EXPRKIND_LIMIT);
        parse->limitCount = preprocess_expression(root, parse->limitCount,
                                                  EXPRKIND_LIMIT);
    
        root->append_rel_list = (List *)
            preprocess_expression(root, (Node *) root->append_rel_list,
                                  EXPRKIND_APPINFO);
    
        /* Also need to preprocess expressions for function and values RTEs */
        foreach(l, parse->rtable)
        {
            RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
    
            if (rte->rtekind == RTE_FUNCTION)
                rte->funcexpr = preprocess_expression(root, rte->funcexpr,
                                                      EXPRKIND_RTFUNC);
            else if (rte->rtekind == RTE_VALUES)
                rte->values_lists = (List *)
                    preprocess_expression(root, (Node *) rte->values_lists,
                                          EXPRKIND_VALUES);
        }

    接着继续,是对HAVING 的处理、对我的简单查询而言,也是可以忽略的。

        /*
         * In some cases we may want to transfer a HAVING clause into WHERE. We
         * cannot do so if the HAVING clause contains aggregates (obviously) or
         * volatile functions (since a HAVING clause is supposed to be executed
         * only once per group).  Also, it may be that the clause is so expensive
         * to execute that we're better off doing it only once per group, despite
         * the loss of selectivity.  This is hard to estimate short of doing the
         * entire planning process twice, so we use a heuristic: clauses
         * containing subplans are left in HAVING.    Otherwise, we move or copy the
         * HAVING clause into WHERE, in hopes of eliminating tuples before
         * aggregation instead of after.
         *
         * If the query has explicit grouping then we can simply move such a
         * clause into WHERE; any group that fails the clause will not be in the
         * output because none of its tuples will reach the grouping or
         * aggregation stage.  Otherwise we must have a degenerate (variable-free)
         * HAVING clause, which we put in WHERE so that query_planner() can use it
         * in a gating Result node, but also keep in HAVING to ensure that we
         * don't emit a bogus aggregated row. (This could be done better, but it
         * seems not worth optimizing.)
         *
         * Note that both havingQual and parse->jointree->quals are in
         * implicitly-ANDed-list form at this point, even though they are declared
         * as Node *.
         */
        newHaving = NIL;
        foreach(l, (List *) parse->havingQual)
        {
            Node       *havingclause = (Node *) lfirst(l);
    
            if (contain_agg_clause(havingclause) ||
                contain_volatile_functions(havingclause) ||
                contain_subplans(havingclause))
            {
                /* keep it in HAVING */
                newHaving = lappend(newHaving, havingclause);
            }
            else if (parse->groupClause)
            {
                /* move it to WHERE */
                parse->jointree->quals = (Node *)
                    lappend((List *) parse->jointree->quals, havingclause);
            }
            else
            {
                /* put a copy in WHERE, keep it in HAVING */
                parse->jointree->quals = (Node *)
                    lappend((List *) parse->jointree->quals,
                            copyObject(havingclause));
                newHaving = lappend(newHaving, havingclause);
            }
        }
        parse->havingQual = (Node *) newHaving;

     接下来的一段,因为我的简单查询没有outer join,所以也可以无视。

        /*
         * If we have any outer joins, try to reduce them to plain inner joins.
         * This step is most easily done after we've done expression
         * preprocessing.
         */
        if (hasOuterJoins)
            reduce_outer_joins(root);

    紧接着,关键的地方就来了:这里叫作 main planning。

        /*
         * Do the main planning.  If we have an inherited target relation, that
         * needs special processing, else go straight to grouping_planner.
         */
        if (parse->resultRelation &&
            rt_fetch(parse->resultRelation, parse->rtable)->inh)
            plan = inheritance_planner(root);
        else
        {
            plan = grouping_planner(root, tuple_fraction);
            /* If it's not SELECT, we need a ModifyTable node */
            if (parse->commandType != CMD_SELECT)
            {
                List       *returningLists;
                List       *rowMarks;
    
                /*
                 * Set up the RETURNING list-of-lists, if needed.
                 */
                if (parse->returningList)
                    returningLists = list_make1(parse->returningList);
                else
                    returningLists = NIL;
    
                /*
                 * If there was a FOR UPDATE/SHARE clause, the LockRows node will
                 * have dealt with fetching non-locked marked rows, else we need
                 * to have ModifyTable do that.
                 */
                if (parse->rowMarks)
                    rowMarks = NIL;
                else
                    rowMarks = root->rowMarks;
    
                plan = (Plan *) make_modifytable(parse->commandType,
                                                 parse->canSetTag,
                                           list_make1_int(parse->resultRelation),
                                                 list_make1(plan),
                                                 returningLists,
                                                 rowMarks,
                                                 SS_assign_special_param(root));
            }
        }

     由于 上面的 parse->resultRelation 是false。 所以,就变成了:

        else
        {
            plan = grouping_planner(root, tuple_fraction);
            /* If it's not SELECT, we need a ModifyTable node */
            if (parse->commandType != CMD_SELECT)
            {
                List       *returningLists;
                List       *rowMarks;
    
                /*
                 * Set up the RETURNING list-of-lists, if needed.
                 */
                if (parse->returningList)
                    returningLists = list_make1(parse->returningList);
                else
                    returningLists = NIL;
    
                /*
                 * If there was a FOR UPDATE/SHARE clause, the LockRows node will
                 * have dealt with fetching non-locked marked rows, else we need
                 * to have ModifyTable do that.
                 */
                if (parse->rowMarks)
                    rowMarks = NIL;
                else
                    rowMarks = root->rowMarks;
    
                plan = (Plan *) make_modifytable(parse->commandType,
                                                 parse->canSetTag,
                                           list_make1_int(parse->resultRelation),
                                                 list_make1(plan),
                                                 returningLists,
                                                 rowMarks,
                                                 SS_assign_special_param(root));
            }
        }

    又由于 parse->commandType != CMD_SELECT 不成立,所以可以简化为:

        else
        {
            plan = grouping_planner(root, tuple_fraction);
                    ...
    
            }
  • 相关阅读:
    五大浏览器内核代表作品
    防止高度塌陷的方法
    过滤器(filter)
    置换元素与非置换元素
    display属性和属性值(18个属性值,常见面试题)
    常见的块级元素、内联元素
    html基础表单
    Windows下使用TensorFlow
    Windows安装TensorFlow-Docker Installation of TensorFlow on Windows
    <Web Scraping with Python>:Chapter 1 & 2
  • 原文地址:https://www.cnblogs.com/gaojian/p/3117446.html
Copyright © 2020-2023  润新知