• PostgreSQL在何处处理 sql查询之五十七


    接着追踪 ->pathlist:

    初始化可能是在这里完成的?

    /*
     * add_path
     *      Consider a potential implementation path for the specified parent rel,
     *      and add it to the rel's pathlist if it is worthy of consideration.
     *      A path is worthy if it has a better sort order (better pathkeys) or
     *      cheaper cost (on either dimension), or generates fewer rows, than any
     *      existing path that has the same or superset parameterization rels.
     *
     *      We also remove from the rel's pathlist any old paths that are dominated
     *      by new_path --- that is, new_path is cheaper, at least as well ordered,
     *      generates no more rows, and requires no outer rels not required by the
     *      old path.
     *
     *      In most cases, a path with a superset parameterization will generate
     *      fewer rows (since it has more join clauses to apply), so that those two
     *      figures of merit move in opposite directions; this means that a path of
     *      one parameterization can seldom dominate a path of another.  But such
     *      cases do arise, so we make the full set of checks anyway.
     *
     *      There is one policy decision embedded in this function, along with its
     *      sibling add_path_precheck: we treat all parameterized paths as having
     *      NIL pathkeys, so that they compete only on cost.    This is to reduce
     *      the number of parameterized paths that are kept.    See discussion in
     *      src/backend/optimizer/README.
     *
     *      The pathlist is kept sorted by total_cost, with cheaper paths
     *      at the front.  Within this routine, that's simply a speed hack:
     *      doing it that way makes it more likely that we will reject an inferior
     *      path after a few comparisons, rather than many comparisons.
     *      However, add_path_precheck relies on this ordering to exit early
     *      when possible.
     *
     *      NOTE: discarded Path objects are immediately pfree'd to reduce planner
     *      memory consumption.  We dare not try to free the substructure of a Path,
     *      since much of it may be shared with other Paths or the query tree itself;
     *      but just recycling discarded Path nodes is a very useful savings in
     *      a large join tree.  We can recycle the List nodes of pathlist, too.
     *
     *      BUT: we do not pfree IndexPath objects, since they may be referenced as
     *      children of BitmapHeapPaths as well as being paths in their own right.
     *
     * 'parent_rel' is the relation entry to which the path corresponds.
     * 'new_path' is a potential path for parent_rel.
     *
     * Returns nothing, but modifies parent_rel->pathlist.
     */
    void
    add_path(RelOptInfo *parent_rel, Path *new_path)
    {
        bool        accept_new = true;        /* unless we find a superior old path */
        ListCell   *insert_after = NULL;    /* where to insert new item */
        List       *new_path_pathkeys;
        ListCell   *p1;
        ListCell   *p1_prev;
        ListCell   *p1_next;
    
        /*
         * This is a convenient place to check for query cancel --- no part of the
         * planner goes very long without calling add_path().
         */
        CHECK_FOR_INTERRUPTS();
    
        /* Pretend parameterized paths have no pathkeys, per comment above */
        new_path_pathkeys = new_path->param_info ? NIL : new_path->pathkeys;
    
        /*
         * Loop to check proposed new path against old paths.  Note it is possible
         * for more than one old path to be tossed out because new_path dominates
         * it.
         *
         * We can't use foreach here because the loop body may delete the current
         * list cell.
         */
        p1_prev = NULL;
        for (p1 = list_head(parent_rel->pathlist); p1 != NULL; p1 = p1_next)
        {
            Path       *old_path = (Path *) lfirst(p1);
            bool        remove_old = false; /* unless new proves superior */
            PathCostComparison costcmp;
            PathKeysComparison keyscmp;
            BMS_Comparison outercmp;
    
            p1_next = lnext(p1);
    
            /*
             * Do a fuzzy cost comparison with 1% fuzziness limit.    (XXX does this
             * percentage need to be user-configurable?)
             */
            costcmp = compare_path_costs_fuzzily(new_path, old_path, 1.01);
    
            /*
             * If the two paths compare differently for startup and total cost,
             * then we want to keep both, and we can skip comparing pathkeys and
             * required_outer rels.  If they compare the same, proceed with the
             * other comparisons.  Row count is checked last.  (We make the tests
             * in this order because the cost comparison is most likely to turn
             * out "different", and the pathkeys comparison next most likely.  As
             * explained above, row count very seldom makes a difference, so even
             * though it's cheap to compare there's not much point in checking it
             * earlier.)
             */
            if (costcmp != COSTS_DIFFERENT)
            {
                /* Similarly check to see if either dominates on pathkeys */
                List       *old_path_pathkeys;
    
                old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
                keyscmp = compare_pathkeys(new_path_pathkeys,
                                           old_path_pathkeys);
                if (keyscmp != PATHKEYS_DIFFERENT)
                {
                    switch (costcmp)
                    {
                        case COSTS_EQUAL:
                            outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
                                                       PATH_REQ_OUTER(old_path));
                            if (keyscmp == PATHKEYS_BETTER1)
                            {
                                if ((outercmp == BMS_EQUAL ||
                                     outercmp == BMS_SUBSET1) &&
                                    new_path->rows <= old_path->rows)
                                    remove_old = true;        /* new dominates old */
                            }
                            else if (keyscmp == PATHKEYS_BETTER2)
                            {
                                if ((outercmp == BMS_EQUAL ||
                                     outercmp == BMS_SUBSET2) &&
                                    new_path->rows >= old_path->rows)
                                    accept_new = false;        /* old dominates new */
                            }
                            else    /* keyscmp == PATHKEYS_EQUAL */
                            {
                                if (outercmp == BMS_EQUAL)
                                {
                                    /*
                                     * Same pathkeys and outer rels, and fuzzily
                                     * the same cost, so keep just one; to decide
                                     * which, first check rows and then do a fuzzy
                                     * cost comparison with very small fuzz limit.
                                     * (We used to do an exact cost comparison,
                                     * but that results in annoying
                                     * platform-specific plan variations due to
                                     * roundoff in the cost estimates.)  If things
                                     * are still tied, arbitrarily keep only the
                                     * old path.  Notice that we will keep only
                                     * the old path even if the less-fuzzy
                                     * comparison decides the startup and total
                                     * costs compare differently.
                                     */
                                    if (new_path->rows < old_path->rows)
                                        remove_old = true;    /* new dominates old */
                                    else if (new_path->rows > old_path->rows)
                                        accept_new = false; /* old dominates new */
                                    else if (compare_path_costs_fuzzily(new_path, old_path,
                                                  1.0000000001) == COSTS_BETTER1)
                                        remove_old = true;    /* new dominates old */
                                    else
                                        accept_new = false; /* old equals or
                                                             * dominates new */
                                }
                                else if (outercmp == BMS_SUBSET1 &&
                                         new_path->rows <= old_path->rows)
                                    remove_old = true;        /* new dominates old */
                                else if (outercmp == BMS_SUBSET2 &&
                                         new_path->rows >= old_path->rows)
                                    accept_new = false;        /* old dominates new */
                                /* else different parameterizations, keep both */
                            }
                            break;
                        case COSTS_BETTER1:
                            if (keyscmp != PATHKEYS_BETTER2)
                            {
                                outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
                                                       PATH_REQ_OUTER(old_path));
                                if ((outercmp == BMS_EQUAL ||
                                     outercmp == BMS_SUBSET1) &&
                                    new_path->rows <= old_path->rows)
                                    remove_old = true;        /* new dominates old */
                            }
                            break;
                        case COSTS_BETTER2:
                            if (keyscmp != PATHKEYS_BETTER1)
                            {
                                outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
                                                       PATH_REQ_OUTER(old_path));
                                if ((outercmp == BMS_EQUAL ||
                                     outercmp == BMS_SUBSET2) &&
                                    new_path->rows >= old_path->rows)
                                    accept_new = false;        /* old dominates new */
                            }
                            break;
                        case COSTS_DIFFERENT:
    
                            /*
                             * can't get here, but keep this case to keep compiler
                             * quiet
                             */
                            break;
                    }
                }
            }
    
            /*
             * Remove current element from pathlist if dominated by new.
             */
            if (remove_old)
            {
                parent_rel->pathlist = list_delete_cell(parent_rel->pathlist,
                                                        p1, p1_prev);
    
                /*
                 * Delete the data pointed-to by the deleted cell, if possible
                 */
                if (!IsA(old_path, IndexPath))
                    pfree(old_path);
                /* p1_prev does not advance */
            }
            else
            {
                /* new belongs after this old path if it has cost >= old's */
                if (new_path->total_cost >= old_path->total_cost)
                    insert_after = p1;
                /* p1_prev advances */
                p1_prev = p1;
            }
    
            /*
             * If we found an old path that dominates new_path, we can quit
             * scanning the pathlist; we will not add new_path, and we assume
             * new_path cannot dominate any other elements of the pathlist.
             */
            if (!accept_new)
                break;
        }
    
        if (accept_new)
        {
            /* Accept the new path: insert it at proper place in pathlist */
            if (insert_after)
                lappend_cell(parent_rel->pathlist, insert_after, new_path);
            else
                parent_rel->pathlist = lcons(new_path, parent_rel->pathlist);
        }
        else
        {
            /* Reject and recycle the new path */
            if (!IsA(new_path, IndexPath))
                pfree(new_path);
        }
    }

    目前为止,追踪遇到可困难,此路暂时不通。

    考虑其他方向。

    这个还是很重要的:

    /*
     * set_plain_rel_pathlist
     *      Build access paths for a plain relation (no subquery, no inheritance)
     */
    static void
    set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
    {
        ///fprintf(stderr,"In set_plain_rel_pathlist \n");
    
        /* Consider sequential scan */
        add_path(rel, create_seqscan_path(root, rel, NULL));
    
        /* Consider index scans */
        create_index_paths(root, rel);
    
        /* Consider TID scans */
        create_tidscan_paths(root, rel);
    
        /* Now find the cheapest of the paths for this rel */
        set_cheapest(rel);
    }
  • 相关阅读:
    javaweb中带标签体的自定义标签
    javaweb带父标签的自定义标签
    Filter的常见应用
    Filter内容
    JFace TableViewer性能改善 -- 使用VirtualTable
    SWT table性能改善 -- 使用VirtualTable
    java自动探测文件的字符编码
    [小技巧]Filezilla无法确定拖放操作目标,由于shell未正确安装__解决办法
    批量导出VBA工程中的Source
    开源许可证知多少
  • 原文地址:https://www.cnblogs.com/gaojian/p/3123869.html
Copyright © 2020-2023  润新知