91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PostgreSQL中grouping_planner函數有什么作用

發布時間:2021-11-10 15:55:59 來源:億速云 閱讀:154 作者:iii 欄目:關系型數據庫

這篇文章主要介紹“PostgreSQL中grouping_planner函數有什么作用”,在日常操作中,相信很多人在PostgreSQL中grouping_planner函數有什么作用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”PostgreSQL中grouping_planner函數有什么作用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

源碼解讀

分組/聚集等操作是在一個Relation上疊加分組/聚集運算,grouping_planner函數首先通過query_planner函數生成一個新的關系,然后在此關系上attached分組/聚集等操作。

/*--------------------
 * grouping_planner
 *    Perform planning steps related to grouping, aggregation, etc.
 *    執行與與分組/聚集相關的"規劃步驟".
 *    分組/聚集等操作是在一個Relation上疊加分組/聚集運算,
 *    PG首先通過query_planner函數生成一個新的關系,然后在此關系上attached分組/聚集等操作
 *
 * This function adds all required top-level processing to the scan/join
 * Path(s) produced by query_planner.
 *
 * 該函數還處理了所有需要在頂層處理的掃描/連接路徑(通過query_planner函數生成)
 *
 * If inheritance_update is true, we're being called from inheritance_planner
 * and should not include a ModifyTable step in the resulting Path(s).
 * (inheritance_planner will create a single ModifyTable node covering all the
 * target tables.)
 *
 * 如果標志inheritance_update為true,這個函數的調用者是inheritance_planner,在結果路徑中
 * 不應包含ModifyTable步驟(inheritance_planner會創建一個單獨的覆蓋所有目標表的ModifyTable節點).
 *
 * tuple_fraction is the fraction of tuples we expect will be retrieved.
 * tuple_fraction is interpreted as follows:
 *    0: expect all tuples to be retrieved (normal case)
 *    0 < tuple_fraction < 1: expect the given fraction of tuples available
 *      from the plan to be retrieved
 *    tuple_fraction >= 1: tuple_fraction is the absolute number of tuples
 *      expected to be retrieved (ie, a LIMIT specification)
 *
 * tuple_fraction是我們希望搜索的元組比例:
 * 0:正常情況下,期望掃描所有的元組
 * 大于0小于1:按給定的比例掃描
 * 大于等于1:掃描的元組數量(比如通過LIMIT語句指定)
 *
 * Returns nothing; the useful output is in the Paths we attach to the
 * (UPPERREL_FINAL, NULL) upperrel in *root.  In addition,
 * root->processed_tlist contains the final processed targetlist.
 *
 * 該函數沒有返回值,有用的輸出是root->upperrel->Paths,另外,root->processed_tlist中存儲最終的投影列
 *
 * Note that we have not done set_cheapest() on the final rel; it's convenient
 * to leave this to the caller.
 *--------------------
 */
static void
grouping_planner(PlannerInfo *root, bool inheritance_update,
                 double tuple_fraction)
{
    Query      *parse = root->parse;
    List       *tlist;
    int64       offset_est = 0;
    int64       count_est = 0;
    double      limit_tuples = -1.0;
    bool        have_postponed_srfs = false;
    PathTarget *final_target;
    List       *final_targets;
    List       *final_targets_contain_srfs;
    bool        final_target_parallel_safe;
    RelOptInfo *current_rel;
    RelOptInfo *final_rel;
    ListCell   *lc;

    /* Tweak caller-supplied tuple_fraction if have LIMIT/OFFSET */
    //如果存在LIMIT/OFFSET子句,調整tuple_fraction
    if (parse->limitCount || parse->limitOffset)//存在LIMIT/OFFSET語句
    {
        tuple_fraction = preprocess_limit(root, tuple_fraction,
                                          &offset_est, &count_est);//獲取元組數量

        /*
         * If we have a known LIMIT, and don't have an unknown OFFSET, we can
         * estimate the effects of using a bounded sort.
         * 如果我們有一個已知LIMIT,并且沒有未知的OFFSET,我們可以估算使用有界排序的效果。
         */
        if (count_est > 0 && offset_est >= 0)
            limit_tuples = (double) count_est + (double) offset_est;//
    }

    /* Make tuple_fraction accessible to lower-level routines */
    //使tuple_fraction可被低級別的處理過程訪問(在優化器信息中設置)
    root->tuple_fraction = tuple_fraction;//設置值

    if (parse->setOperations)//集合操作,如UNION等
    {
        /*
         * If there's a top-level ORDER BY, assume we have to fetch all the
         * tuples.  This might be too simplistic given all the hackery below
         * to possibly avoid the sort; but the odds of accurate estimates here
         * are pretty low anyway.  XXX try to get rid of this in favor of
         * letting plan_set_operations generate both fast-start and
         * cheapest-total paths.
         * 如果語句的最外層(頂級)存在ORDER BY子句,假設我們必須獲取所有元組。
         * 這可能過于簡單,但無論如何,準確估計的幾率是相當低的。
         * XXX試圖擺脫這種情況,讓plan_set_operations同時生成快速啟動和最便宜的路徑。
         */
        if (parse->sortClause)
            root->tuple_fraction = 0.0;//存在排序操作,需掃描所有的元組

        /*
         * Construct Paths for set operations.  The results will not need any
         * work except perhaps a top-level sort and/or LIMIT.  Note that any
         * special work for recursive unions is the responsibility of
         * plan_set_operations.
         * 為集合操作構造路徑。
         * 除了最外層的SORT/LIMIT操作外不需要作其他操作。
注意,遞歸聯合的任何特殊工作都是plan_set_operations負責。
         */
        current_rel = plan_set_operations(root);//調用集合操作的"規劃"函數

        /*
         * We should not need to call preprocess_targetlist, since we must be
         * in a SELECT query node.  Instead, use the targetlist returned by
         * plan_set_operations (since this tells whether it returned any
         * resjunk columns!), and transfer any sort key information from the
         * original tlist.
         * 我們不需要調用preprocess_targetlist函數,因為執行這些操作必須在SELECT查詢NODE中。
         * 相反,使用plan_set_operations函數返回的targetlist(因為這告訴它是否返回了所有的resjunk列),
         * 并從原始投影列鏈表tlist中傳輸所有的排序sort鍵信息。
         */
        Assert(parse->commandType == CMD_SELECT);

        tlist = root->processed_tlist;  /* 從plan_set_operations函數的返回結果中獲取;from plan_set_operations */

        /* for safety, copy processed_tlist instead of modifying in-place */
        //為了安全起見,復制processed_tlist,而不是就地修改
        tlist = postprocess_setop_tlist(copyObject(tlist), parse->targetList);

        /* Save aside the final decorated tlist */
        //
        root->processed_tlist = tlist;

        /* Also extract the PathTarget form of the setop result tlist */
        //從集合操作結果投影列中獲取PathTarget格式的結果列
        final_target = current_rel->cheapest_total_path->pathtarget;

        /* And check whether it's parallel safe */
        //檢查是否并行安全
        final_target_parallel_safe =
            is_parallel_safe(root, (Node *) final_target->exprs);

        /* The setop result tlist couldn't contain any SRFs */
        //集合操作結果投影列不能包含任何的SRFs
        Assert(!parse->hasTargetSRFs);
        final_targets = final_targets_contain_srfs = NIL;

        /*
         * Can't handle FOR [KEY] UPDATE/SHARE here (parser should have
         * checked already, but let's make sure).
         * 無法在這里處理[KEY]更新/共享(解析器應該已經檢查過了,但需要確認)。
         */
        if (parse->rowMarks)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
            /*------
              translator: %s is a SQL row locking clause such as FOR UPDATE */
                     errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
                            LCS_asString(linitial_node(RowMarkClause,
                                                       parse->rowMarks)->strength))));

        /*
         * Calculate pathkeys that represent result ordering requirements
         * 計算表示結果排序需求的pathkeys
         */
        Assert(parse->distinctClause == NIL);
        root->sort_pathkeys = make_pathkeys_for_sortclauses(root,
                                                            parse->sortClause,
                                                            tlist);
    }
    else//非集合操作
    {
        /* No set operations, do regular planning */
        //沒有集合操作,執行常規的規劃過程
        PathTarget *sort_input_target;
        List       *sort_input_targets;
        List       *sort_input_targets_contain_srfs;
        bool        sort_input_target_parallel_safe;
        PathTarget *grouping_target;
        List       *grouping_targets;
        List       *grouping_targets_contain_srfs;
        bool        grouping_target_parallel_safe;
        PathTarget *scanjoin_target;
        List       *scanjoin_targets;
        List       *scanjoin_targets_contain_srfs;
        bool        scanjoin_target_parallel_safe;
        bool        scanjoin_target_same_exprs;
        bool        have_grouping;
        AggClauseCosts agg_costs;
        WindowFuncLists *wflists = NULL;
        List       *activeWindows = NIL;
        grouping_sets_data *gset_data = NULL;
        standard_qp_extra qp_extra;

        /* A recursive query should always have setOperations */
        //遞歸查詢應包含集合操作,檢查!
        Assert(!root->hasRecursion);//檢查

        /* Preprocess grouping sets and GROUP BY clause, if any */
        //預處理grouping sets語句和GROUP BY 子句
        if (parse->groupingSets)//
        {
            gset_data = preprocess_grouping_sets(root);//預處理grouping sets語句
        }
        else
        {
            /* Preprocess regular GROUP BY clause, if any */
            //如處理常規的GROUP BY 子句
            if (parse->groupClause)
                parse->groupClause = preprocess_groupclause(root, NIL);//處理普通的Group By語句
        }

        /* Preprocess targetlist */
        //預處理投影列
        tlist = preprocess_targetlist(root);//處理投影列

        /*
         * We are now done hacking up the query's targetlist.  Most of the
         * remaining planning work will be done with the PathTarget
         * representation of tlists, but save aside the full representation so
         * that we can transfer its decoration (resnames etc) to the topmost
         * tlist of the finished Plan.
         * 現在已經完成了對查詢語句targetlist的hacking工作。
         * 剩下的大部分規劃工作將使用tlists的PathTarget來完成,
         * 但是需要保留完整的信息,這樣我們就可以將它的修飾信息(如resname等)轉移到完成計劃的最頂層tlist中。
         */
        root->processed_tlist = tlist;//賦值

        /*
         * Collect statistics about aggregates for estimating costs, and mark
         * all the aggregates with resolved aggtranstypes.  We must do this
         * before slicing and dicing the tlist into various pathtargets, else
         * some copies of the Aggref nodes might escape being marked with the
         * correct transtypes.
         * 收集關于聚集操作的統計數據以估計成本,并在所有聚集操作上標上已解決的aggtranstypes。
         * 必須在將tlist切割成各種PathKeys之前完成這項工作,
         * 否則一些Aggref節點的副本中正確transtypes可能會被替換。
         * 
         * Note: currently, we do not detect duplicate aggregates here.  This
         * may result in somewhat-overestimated cost, which is fine for our
         * purposes since all Paths will get charged the same.  But at some
         * point we might wish to do that detection in the planner, rather
         * than during executor startup.
         * 注意:目前,我們沒有檢測到重復的聚合。
         * 這可能會導致一些過高估算的成本,這對于我們的目的來說是好的,因為所有的Path都會耗費相同的成本。
         * 但在某些時候,可能希望在計劃器中進行檢測,而不是在執行器executor啟動期間。
         */
        MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
        if (parse->hasAggs)//存在聚合函數
        {
            get_agg_clause_costs(root, (Node *) tlist, AGGSPLIT_SIMPLE,
                                 &agg_costs);//收集用于估算成本的統計信息
            get_agg_clause_costs(root, parse->havingQual, AGGSPLIT_SIMPLE,
                                 &agg_costs);//收集用于估算成本的統計信息
        }

        /*
         * Locate any window functions in the tlist.  (We don't need to look
         * anywhere else, since expressions used in ORDER BY will be in there
         * too.)  Note that they could all have been eliminated by constant
         * folding, in which case we don't need to do any more work.
         * 在tlist中找到所有的窗口函數。
         * (我們不需要在其他地方查找,因為ORDER BY中使用的表達式也在那里。)
         * 注意,它們可以通過不斷折疊來消除,在這種情況下,我們不需要做更多的工作。
         */
        if (parse->hasWindowFuncs)//窗口函數
        {
            wflists = find_window_functions((Node *) tlist,
                                            list_length(parse->windowClause));
            if (wflists->numWindowFuncs > 0)
                activeWindows = select_active_windows(root, wflists);
            else
                parse->hasWindowFuncs = false;
        }

        /*
         * Preprocess MIN/MAX aggregates, if any.  Note: be careful about
         * adding logic between here and the query_planner() call.  Anything
         * that is needed in MIN/MAX-optimizable cases will have to be
         * duplicated in planagg.c.
         * 重新處理MAX/MIN聚集操作,如果有的話。
         * 注意:在這里和query_planner()調用之間添加邏輯時要小心。
         * 在MIN/MAX優化情況下需要的所有東西都必須在plan .c中重復。
         */
        if (parse->hasAggs)//預處理最大最小聚合
            preprocess_minmax_aggregates(root, tlist);

        /*
         * Figure out whether there's a hard limit on the number of rows that
         * query_planner's result subplan needs to return.  Even if we know a
         * hard limit overall, it doesn't apply if the query has any
         * grouping/aggregation operations, or SRFs in the tlist.
         * 計算query_planner結果子計劃需要返回的行數是否有硬性限制。
         * 即使我們知道總的強制限制,如果查詢在tlist中有任何分組/聚合操作或SRFs,它也不適用。
         */
        if (parse->groupClause ||
            parse->groupingSets ||
            parse->distinctClause ||
            parse->hasAggs ||
            parse->hasWindowFuncs ||
            parse->hasTargetSRFs ||
            root->hasHavingQual)//存在Group By/Grouping Set等語句,則limit_tuples設置為-1
            root->limit_tuples = -1.0;
        else
            root->limit_tuples = limit_tuples;//否則,正常賦值

        /* Set up data needed by standard_qp_callback */
        //配置standard_qp_callback函數需要的相關數據
        qp_extra.tlist = tlist;//賦值
        qp_extra.activeWindows = activeWindows;
        qp_extra.groupClause = (gset_data
                                ? (gset_data->rollups ? linitial_node(RollupData, gset_data->rollups)->groupClause : NIL)
                                : parse->groupClause);

        /*
         * Generate the best unsorted and presorted paths for the scan/join
         * portion of this Query, ie the processing represented by the
         * FROM/WHERE clauses.  (Note there may not be any presorted paths.)
         * We also generate (in standard_qp_callback) pathkey representations
         * of the query's sort clause, distinct clause, etc.
         * 為這個查詢的掃描/連接部分(即FROM/WHERE子句表示的處理)生成最好的未排序和預排序路徑。
         * (注意,可能沒有任何預先設置的路徑。)
         * 我們還生成(在standard_qp_callback中)查詢語句的sort子句和distinct子句對應的PathKey。
         */
         //為查詢中的掃描/連接部分生成最優的未排序/預排序路徑(如FROM/WHERE語句表示的處理過程)
        current_rel = query_planner(root, tlist,
                                    standard_qp_callback, &qp_extra);

        /*
         * Convert the query's result tlist into PathTarget format.
         * 轉換查詢結果為PathTarget格式
         *
         * Note: it's desirable to not do this till after query_planner(),
         * because the target width estimates can use per-Var width numbers
         * that were obtained within query_planner().
         * 注意:在query_planner()之后才需要這樣做,因為目標列的寬度估算可以使用在query_planner()中獲得的每個VAR信息。
         */
        final_target = create_pathtarget(root, tlist);
        final_target_parallel_safe =
            is_parallel_safe(root, (Node *) final_target->exprs);

        /*
         * If ORDER BY was given, consider whether we should use a post-sort
         * projection, and compute the adjusted target for preceding steps if
         * so.
         * 如果存在ORDER BY子句,考慮是否使用post-sort投影,如使用則計算前面已調整過的步驟目標列。
         */
        if (parse->sortClause)//存在sort語句?
        {
            sort_input_target = make_sort_input_target(root,
                                                       final_target,
                                                       &have_postponed_srfs);
            sort_input_target_parallel_safe =
                is_parallel_safe(root, (Node *) sort_input_target->exprs);
        }
        else
        {
            sort_input_target = final_target;//不存在,則直接賦值
            sort_input_target_parallel_safe = final_target_parallel_safe;
        }

        /*
         * If we have window functions to deal with, the output from any
         * grouping step needs to be what the window functions want;
         * otherwise, it should be sort_input_target.
         * 如果要處理窗口函數,任何分組步驟的輸出都需要滿足窗口函數的要求;
         * 否則,它應該是sort_input_target。
         */
        if (activeWindows)//存在窗口函數?
        {
            grouping_target = make_window_input_target(root,
                                                       final_target,
                                                       activeWindows);
            grouping_target_parallel_safe =
                is_parallel_safe(root, (Node *) grouping_target->exprs);
        }
        else
        {
            grouping_target = sort_input_target;
            grouping_target_parallel_safe = sort_input_target_parallel_safe;
        }

        /*
         * If we have grouping or aggregation to do, the topmost scan/join
         * plan node must emit what the grouping step wants; otherwise, it
         * should emit grouping_target.
         * 如果要進行分組或聚合,最外層的掃描/連接計劃節點必須發出分組步驟需要的內容;
         * 否則,它應該設置grouping_target。
         */
        have_grouping = (parse->groupClause || parse->groupingSets ||
                         parse->hasAggs || root->hasHavingQual);
        if (have_grouping)
        {//存在group等分組語句
            scanjoin_target = make_group_input_target(root, final_target);
            scanjoin_target_parallel_safe =
                is_parallel_safe(root, (Node *) grouping_target->exprs);
        }
        else
        {
            scanjoin_target = grouping_target;
            scanjoin_target_parallel_safe = grouping_target_parallel_safe;
        }

        /*
         * If there are any SRFs in the targetlist, we must separate each of
         * these PathTargets into SRF-computing and SRF-free targets.  Replace
         * each of the named targets with a SRF-free version, and remember the
         * list of additional projection steps we need to add afterwards.
         * 如果targetlist中有任何SRFs,我們必須將這些PathKeys分別劃分為SRF-computing和SRF-free 目標列。
         * 用一個沒有SRF的版本替換每個指定的目標,并記住后面需要添加的其他投影步驟鏈表。
         */
        if (parse->hasTargetSRFs)//存在SRFs
        {
            /* final_target doesn't recompute any SRFs in sort_input_target */
            //在sort_input_target中不需要重復計算SRFs
            split_pathtarget_at_srfs(root, final_target, sort_input_target,
                                     &final_targets,
                                     &final_targets_contain_srfs);
            final_target = linitial_node(PathTarget, final_targets);
            Assert(!linitial_int(final_targets_contain_srfs));
            /* likewise for sort_input_target vs. grouping_target */
            split_pathtarget_at_srfs(root, sort_input_target, grouping_target,
                                     &sort_input_targets,
                                     &sort_input_targets_contain_srfs);
            sort_input_target = linitial_node(PathTarget, sort_input_targets);
            Assert(!linitial_int(sort_input_targets_contain_srfs));
            /* likewise for grouping_target vs. scanjoin_target */
            split_pathtarget_at_srfs(root, grouping_target, scanjoin_target,
                                     &grouping_targets,
                                     &grouping_targets_contain_srfs);
            grouping_target = linitial_node(PathTarget, grouping_targets);
            Assert(!linitial_int(grouping_targets_contain_srfs));
            /* scanjoin_target will not have any SRFs precomputed for it */
            split_pathtarget_at_srfs(root, scanjoin_target, NULL,
                                     &scanjoin_targets,
                                     &scanjoin_targets_contain_srfs);
            scanjoin_target = linitial_node(PathTarget, scanjoin_targets);
            Assert(!linitial_int(scanjoin_targets_contain_srfs));
        }
        else
        {
            /* initialize lists; for most of these, dummy values are OK */
            //初始化鏈表
            final_targets = final_targets_contain_srfs = NIL;
            sort_input_targets = sort_input_targets_contain_srfs = NIL;
            grouping_targets = grouping_targets_contain_srfs = NIL;
            scanjoin_targets = list_make1(scanjoin_target);
            scanjoin_targets_contain_srfs = NIL;
        }

        /* Apply scan/join target. */
         //應用掃描/連接target
        scanjoin_target_same_exprs = list_length(scanjoin_targets) == 1
            && equal(scanjoin_target->exprs, current_rel->reltarget->exprs);
        apply_scanjoin_target_to_paths(root, current_rel, scanjoin_targets,
                                       scanjoin_targets_contain_srfs,
                                       scanjoin_target_parallel_safe,
                                       scanjoin_target_same_exprs);

        /*
         * Save the various upper-rel PathTargets we just computed into
         * root->upper_targets[].  The core code doesn't use this, but it
         * provides a convenient place for extensions to get at the info.  For
         * consistency, we save all the intermediate targets, even though some
         * of the corresponding upperrels might not be needed for this query.
         * 保存剛剛計算的各種upper- >upper_targets[]信息。
         * 核心代碼不使用這個功能,但是它為擴展提供了一個方便的地方來獲取信息。
         * 為了保持一致性,我們保存了所有的中間目標列,即使這個查詢可能不需要一些相應的上層關系。
         */
         //賦值
        root->upper_targets[UPPERREL_FINAL] = final_target;
        root->upper_targets[UPPERREL_WINDOW] = sort_input_target;
        root->upper_targets[UPPERREL_GROUP_AGG] = grouping_target;

        /*
         * If we have grouping and/or aggregation, consider ways to implement
         * that.  We build a new upperrel representing the output of this
         * phase.
         * 如果我們有分組和/或聚合,考慮如何實現它。需要構建一個表示此階段輸出的上層關系。
         */
        if (have_grouping)//存在分組操作
        {
            current_rel = create_grouping_paths(root,
                                                current_rel,
                                                grouping_target,
                                                grouping_target_parallel_safe,
                                                &agg_costs,
                                                gset_data);//創建分組訪問路徑
            /* Fix things up if grouping_target contains SRFs */
            if (parse->hasTargetSRFs)
                adjust_paths_for_srfs(root, current_rel,
                                      grouping_targets,
                                      grouping_targets_contain_srfs);
        }

        /*
         * If we have window functions, consider ways to implement those.  We
         * build a new upperrel representing the output of this phase.
         * 如果有窗口函數,考慮如何實現這些函數。
         * 我們建立一個新的上層關系表示這個階段的輸出。
         */
        if (activeWindows)//存在窗口函數
        {
            current_rel = create_window_paths(root,
                                              current_rel,
                                              grouping_target,
                                              sort_input_target,
                                              sort_input_target_parallel_safe,
                                              tlist,
                                              wflists,
                                              activeWindows);
            /* Fix things up if sort_input_target contains SRFs */
            if (parse->hasTargetSRFs)
                adjust_paths_for_srfs(root, current_rel,
                                      sort_input_targets,
                                      sort_input_targets_contain_srfs);
        }

        /*
         * If there is a DISTINCT clause, consider ways to implement that. We
         * build a new upperrel representing the output of this phase.
         * 如果有一個DISTINCT子句,考慮如何實現它。構建一個表示此階段輸出的上層關系。
         */
        if (parse->distinctClause)//存在distinct?
        {
            current_rel = create_distinct_paths(root,
                                                current_rel);
        }
    }                           /* end of if (setOperations) */

    /*
     * If ORDER BY was given, consider ways to implement that, and generate a
     * new upperrel containing only paths that emit the correct ordering and
     * project the correct final_target.  We can apply the original
     * limit_tuples limit in sort costing here, but only if there are no
     * postponed SRFs.
     * 如果指定了ORDER BY,考慮實現它的方法,并生成一個僅包含ORDER和final_target的Path的上層關系。
     * 我們可以在排序成本中應用初始的limit_tuples限制,但前提是沒有延遲的SRFs。
     */
    if (parse->sortClause)//存在sort語句?
    {
        current_rel = create_ordered_paths(root,
                                           current_rel,
                                           final_target,
                                           final_target_parallel_safe,
                                           have_postponed_srfs ? -1.0 :
                                           limit_tuples);
        /* Fix things up if final_target contains SRFs */
        if (parse->hasTargetSRFs)
            adjust_paths_for_srfs(root, current_rel,
                                  final_targets,
                                  final_targets_contain_srfs);
    }

    /*
     * Now we are prepared to build the final-output upperrel.
     * 可以構建最終的關系了!
     */
    final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);//獲取最終的RelOptInfo(用于替換RTE)

    /*
     * If the input rel is marked consider_parallel and there's nothing that's
     * not parallel-safe in the LIMIT clause, then the final_rel can be marked
     * consider_parallel as well.  Note that if the query has rowMarks or is
     * not a SELECT, consider_parallel will be false for every relation in the
     * query.
     * 如果關系被標記為consider_parallel,并且在LIMIT子句中沒有任何非并行安全的地方,
     * 那么final_rel也可以被標記為consider_parallel。
     * 請注意,如果查詢有rowMarks或不是SELECT語句,則認為對查詢中的每個關系consider_parallel都為false。
     */
    if (current_rel->consider_parallel &&
        is_parallel_safe(root, parse->limitOffset) &&
        is_parallel_safe(root, parse->limitCount))
        final_rel->consider_parallel = true;//并行

    /*
     * If the current_rel belongs to a single FDW, so does the final_rel.
     * 如current_rel屬于某個單獨的FDW,設置final_rel信息
     */
    final_rel->serverid = current_rel->serverid;
    final_rel->userid = current_rel->userid;
    final_rel->useridiscurrent = current_rel->useridiscurrent;
    final_rel->fdwroutine = current_rel->fdwroutine;

    /*
     * Generate paths for the final_rel.  Insert all surviving paths, with
     * LockRows, Limit, and/or ModifyTable steps added if needed.
     * 為final_rel生成訪問路徑.
     * 插入所有篩選后的訪問路徑,包含需添加的LockRows/Limit/ModifyTable步驟
     */
    foreach(lc, current_rel->pathlist)//逐一遍歷訪問路徑
    {
        Path       *path = (Path *) lfirst(lc);

        /*
         * If there is a FOR [KEY] UPDATE/SHARE clause, add the LockRows node.
         * (Note: we intentionally test parse->rowMarks not root->rowMarks
         * here.  If there are only non-locking rowmarks, they should be
         * handled by the ModifyTable node instead.  However, root->rowMarks
         * is what goes into the LockRows node.)
         * 如果存在FOR [KEY] UPDATE/SHARE子句,則添加LockRows節點。
         * (注意:我們在這里有意測試的是parse->rowMarks,而不是root->rowMarks。
         * 如果只有非鎖定行標記,則應該由ModifyTable節點處理。
         * 但是,root->rowMarks是進入LockRows節點的行標記。
         */
        if (parse->rowMarks)
        {
            path = (Path *) create_lockrows_path(root, final_rel, path,
                                                 root->rowMarks,
                                                 SS_assign_special_param(root));
        }

        /*
         * If there is a LIMIT/OFFSET clause, add the LIMIT node.
         * 如果存在LIMIT/OFFSET子句,添加LIMIT節點
         */
        if (limit_needed(parse))
        {
            path = (Path *) create_limit_path(root, final_rel, path,
                                              parse->limitOffset,
                                              parse->limitCount,
                                              offset_est, count_est);
        }

        /*
         * If this is an INSERT/UPDATE/DELETE, and we're not being called from
         * inheritance_planner, add the ModifyTable node.
         * 如為INSERT/UPDATE/DELETE,而且不是從inheritance_planner函數中調用,則添加ModifyTable節點
         */
        if (parse->commandType != CMD_SELECT && !inheritance_update)//非查詢語句
        {
            List       *withCheckOptionLists;
            List       *returningLists;
            List       *rowMarks;

            /*
             * Set up the WITH CHECK OPTION and RETURNING lists-of-lists, if
             * needed.
             * 如需要,添加WITH CHECK OPTION and RETURNING信息
             */
            if (parse->withCheckOptions)
                withCheckOptionLists = list_make1(parse->withCheckOptions);
            else
                withCheckOptionLists = NIL;

            if (parse->returningList)
                returningLists = list_make1(parse->returningList);
            else
                returningLists = NIL;

            /*
             * If there was a FOR [KEY] UPDATE/SHARE clause, the LockRows node
             * will have dealt with fetching non-locked marked rows, else we
             * need to have ModifyTable do that.
             * 如果存在FOR [KEY] UPDATE/SHARE子句,那么LockRows節點將處理獲取非帶鎖標記的行,
             * 否則我們需要使用ModifyTable來完成。
             */
            if (parse->rowMarks)
                rowMarks = NIL;
            else
                rowMarks = root->rowMarks;

            path = (Path *)
                create_modifytable_path(root, final_rel,
                                        parse->commandType,
                                        parse->canSetTag,
                                        parse->resultRelation,
                                        NIL,
                                        false,
                                        list_make1_int(parse->resultRelation),
                                        list_make1(path),
                                        list_make1(root),
                                        withCheckOptionLists,
                                        returningLists,
                                        rowMarks,
                                        parse->onConflict,
                                        SS_assign_special_param(root));
        }

        /* And shove it into final_rel */
        //添加到final_rel中
        add_path(final_rel, path);
    }

    /*
     * Generate partial paths for final_rel, too,xxwssssssssssssssssss if outer query levels might
     * be able to make use of them.
     * 并行執行訪問路徑
     */
    if (final_rel->consider_parallel && root->query_level > 1 &&
        !limit_needed(parse))
    {
        Assert(!parse->rowMarks && parse->commandType == CMD_SELECT);
        foreach(lc, current_rel->partial_pathlist)
        {
            Path       *partial_path = (Path *) lfirst(lc);

            add_partial_path(final_rel, partial_path);
        }
    }

    /*
     * If there is an FDW that's responsible for all baserels of the query,
     * let it consider adding ForeignPaths.
     * 如查詢中存在FDW,添加ForeignPaths
     */
    if (final_rel->fdwroutine &&
        final_rel->fdwroutine->GetForeignUpperPaths)
        final_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_FINAL,
                                                    current_rel, final_rel,
                                                    NULL);

    /* Let extensions possibly add some more paths */
    //通過擴展添加訪問路徑
    if (create_upper_paths_hook)
        (*create_upper_paths_hook) (root, UPPERREL_FINAL,
                                    current_rel, final_rel, NULL);

    /* Note: currently, we leave it to callers to do set_cheapest() */
    //注意:目前的做法是讓調用放來執行set_cheap()函數
}

到此,關于“PostgreSQL中grouping_planner函數有什么作用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

巴青县| 汝州市| 康马县| 庐江县| 渭南市| 章丘市| 江都市| 翁源县| 丘北县| 谷城县| 丰顺县| 灌南县| 鱼台县| 吴桥县| 大名县| 麻栗坡县| 手机| 开封县| 黄平县| 汪清县| 雅安市| 武邑县| 婺源县| 同心县| 大田县| 云梦县| 东安县| 东方市| 定日县| 桐梓县| 大新县| 郎溪县| 长宁区| 陵水| 遂宁市| 陆丰市| 简阳市| 额敏县| 博罗县| 安庆市| 广宁县|