zoukankan      html  css  js  c++  java
  • 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);
                    ...
    
            }
  • 相关阅读:
    艾伟_转载:你知道吗?——ASP.NET的Session会导致的性能问题 狼人:
    艾伟_转载:一次挂死(hang)的处理过程及经验 狼人:
    艾伟也谈项目管理,微型项目实践感悟 狼人:
    艾伟_转载:[原创]再谈IIS与ASP.NET管道 狼人:
    艾伟_转载:企业库缓存依赖的实现基于文件依赖 狼人:
    艾伟也谈项目管理,我也发软件开发团队的思考(侧重点是人员) 狼人:
    MYSQL用户名:root
    map 和 unordered_map以char * 为key
    设计模式单例模式(singleton)
    Android允许其他应用程序启动你的Activity
  • 原文地址:https://www.cnblogs.com/gaojian/p/3117446.html
Copyright © 2011-2022 走看看