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);
                ...

        }

 

posted @ 2013-06-05 09:36  健哥的数据花园  阅读(408)  评论(0编辑  收藏  举报