您好,登錄后才能下訂單哦!
這篇文章主要介紹“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函數有什么作用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。