What is the main implementation logic of the master planning function make_one_rel in query_planner in PostgreSQL?
This article mainly introduces "what is the main implementation logic of make_one_rel in query_planner in PostgreSQL". In daily operation, I believe that many people have doubts about what is the main implementation logic of make_one_rel in query_planner in PostgreSQL. The editor consulted all kinds of materials and sorted out simple and useful operation methods. I hope it will be helpful to answer the question of "what is the main implementation logic of the main planning function make_one_rel in query_planner in PostgreSQL"! Next, please follow the editor to study!
Query_planner code snippet:
/ /... / * * Ready to do the primary planning. * / final_rel = make_one_rel (root, joinlist); / / execute the main planning process / * Check that we got at least one usable path * / if (! final_rel | |! final_rel- > cheapest_total_path | | final_rel- > cheapest_total_path- > param_info! = NULL) elog (ERROR, "failed to construct the join relation"); / / check the result returned by return final_rel;//. I. data structure
RelOptInfo
Typedef struct RelOptInfo {NodeTag type;// node identifies RelOptKind reloptkind;//RelOpt type / * all relations included in this RelOptInfo * / Relids relids; / * Relids (rtindex) collection set of base relids (rangetable indexes) * / * size estimates generated by planner * / double rows / * does the estimated number of tuples estimated number of result tuples * / / * per-relation planner control flags * / bool consider_startup; / * consider the startup cost? Yes, do you need to keep the path keep cheap-startup-cost paths with low startup cost? * / bool consider_param_startup; / * do you want to consider parameterization? Does the path ditto, for parameterized paths? * / bool consider_parallel; / * consider parallel processing path consider parallel paths? * / * default result targetlist for Paths scanning this relation * / struct PathTarget * reltarget; / * when scanning the Relation, the default result list of Vars/Exprs, cost, width * / * materialization information * / List * pathlist; / * access path list Path structures * / List * ppilist / * ParamPathInfos used in pathlist using parameterized paths in the path list * / List * partial_pathlist; / * partial Paths * / struct Path * cheapest_startup_path;// the lowest startup path struct Path * cheapest_total_path;// the lowest overall path struct Path * cheapest_unique_path;// the path List * cheapest_parameterized_paths with the lowest cost to get a unique value / / the lowest cost parameterization? Path linked list / * parameterization information needed for both base rels and join rels * / * (see also lateral_vars and lateral_referencers) * / Relids direct_lateral_relids; / * uses explicit syntax and depends on Relids rels directly laterally referenced * / Relids lateral_relids The data structure Index relid; / * Relation ID * / Oid reltablespace; / * tablespace containing tablespace * / RTEKind rtekind; / * base table used in / * minimum parameterization of rel * / * information about a base rel (not set for join rels!) * / reloptkind=RELOPT_BASEREL? Subquery? Or functions and so on? RELATION, SUBQUERY, FUNCTION, etc * / AttrNumber min_attr; / * lowest attribute number smallest attrno of rel (often all_baserels = NULL; for (rti = 1; rti)
< root->Simple_rel_array_size; rti++) / / traversing RelOptInfo {RelOptInfo * brel = root- > simple_rel_ Array [RTI]; / * there may be empty slots corresponding to non-baserel RTEs * / if (brel = = NULL) continue; Assert (brel- > relid = = rti) / * sanity check on array * / * ignore RTEs that are "other rels" * / if (brel- > reloptkind! = RELOPT_BASEREL) continue; root- > all_baserels = bms_add_member (root- > all_baserels, brel- > relid) / / add to all_baserels traversal} / * Mark baserels as to whether we care about fast-start plans * / / set the consider_param_startup variable of RelOptInfo, whether to consider fast-start plans set_base_rel_consider_startup (root); / * Compute size estimates and consider_parallel flags for each baserel, * then generate access paths. * / set_base_rel_sizes (root); / / estimate the Size of Relation and set the consider_parallel flag set_base_rel_pathlists (root); / / generate the scanning (access) path of Relation / * * Generate access paths for the entire join tree. * generate the connection path through dynamic programming or genetic algorithm * / rel = make_rel_from_joinlist (root, joinlist); / * The result should join all and only the query's base rels. * / Assert (bms_equal (rel- > relids, root- > all_baserels)); / / return the top RelOptInfo return rel } / /-- / * * set_base_rel_consider_startup * Set the consider_ [param_] startup flags for each base-relation entry. * * For the moment, we only deal with consider_param_startup here; because the * logic for consider_startup is pretty trivial and is the same for every base * relation, we just let build_simple_rel () initialize that flag correctly to * start with. If that logic ever gets more complicated it would probably * be better to move it here. * / static void set_base_rel_consider_startup (PlannerInfo * root) {/ * Since parameterized paths can only be used on the inside of a nestloop * join plan, there is usually little value in considering fast-start * plans for them. However, for relations that are on the RHS of a SEMI * or ANTI join, a fast-start plan can be useful because we're only going * to care about fetching one tuple anyway. * * To minimize growth of planning time, we currently restrict this to * cases where the RHS is a single base relation, not a join; there is no * provision for consider_param_startup to get set at all on joinrels. * Also we don't worry about appendrels. Costsize.c's costing rules for * nestloop semi/antijoins don't consider such cases either. * / ListCell * lc; foreach (lc, root- > join_info_list) {SpecialJoinInfo * sjinfo = (SpecialJoinInfo *) lfirst (lc); int varno If ((sjinfo- > jointype = = JOIN_SEMI | | sjinfo- > jointype = = JOIN_ANTI) & & bms_get_singleton_member (sjinfo- > syn_righthand, & varno)) {RelOptInfo * rel = find_base_rel (root, varno); rel- > consider_param_startup = true } / /-- / * * set_base_rel_sizes * Set the size estimates (rows and widths) for each base-relation entry. * Also determine whether to consider parallel paths for base relations. * * We do this in a separate pass over the base rels so that rowcount * estimates are available for parameterized path generation, and also so * that each rel's consider_parallel flag is set correctly before we begin to * generate paths. * / static void set_base_rel_sizes (PlannerInfo * root) {Index rti; for (rti = 1; rti)
< root->Simple_rel_array_size; rti++) / / traversing the RelOptInfo array {RelOptInfo * rel = root- > simple_rel_ array [RTI]; RangeTblEntry * rte; / * there may be empty slots corresponding to non-baserel RTEs * / if (rel = = NULL) continue; Assert (rel- > relid = = rti) / * sanity check on array * / * ignore RTEs that are "other rels" * / if (rel- > reloptkind! = RELOPT_BASEREL) continue; rte = root- > simple_rte_ array [RTI]; / * If parallelism is allowable for this query in general, see whether * it's allowable for this rel in particular. We have to do this * before set_rel_size (), because (a) if this rel is an inheritance * parent, set_append_rel_size () will use and perhaps change the rel's * consider_parallel flag, and (b) for some RTE types, set_rel_size () * goes ahead and makes paths immediately. * / if (root- > glob- > parallelModeOK) set_rel_consider_parallel (root, rel, rte); set_rel_size (root, rel, rti, rte) }} / * * set_rel_size * Set size estimates for a base relation * / static void set_rel_size (PlannerInfo * root, RelOptInfo * rel, Index rti, RangeTblEntry * rte) {if (rel- > reloptkind = = RELOPT_BASEREL & & relation_excluded_by_constraints (root, rel, rte)) {/ * We proved we don't need to scan the rel via constraint exclusion * so set up a single dummy path for it. Here we only check this for * regular baserels; if it's an otherrel, CE was already checked in * set_append_rel_size (). * In this case, we go ahead and set up the relation's path right away * instead of leaving it for set_rel_pathlist to do. This is because * we don't have a convention for marking a rel as dummy except by * assigning a dummy path to it. * / set_dummy_rel_pathlist (rel); / /} else if (rte- > inh) / / inherit table {/ * It's an "append relation", process accordingly * / set_append_rel_size (root, rel, rti, rte) } else {switch (rel- > rtekind) {case RTE_RELATION:// data Table if (rte- > relkind = = RELKIND_FOREIGN_TABLE) / / FDW {/ * Foreign table * / set_foreign_size (root, rel, rte) } else if (rte- > relkind = = RELKIND_PARTITIONED_TABLE) / / partition table {/ * * A partitioned table without any partitions is marked as * a dummy rel. * / set_dummy_rel_pathlist (rel);} else if (rte- > tablesample! = NULL) / / sampling table {/ * Sampled relation * / set_tablesample_rel_size (root, rel, rte) } else {/ * Plain relation * / set_plain_rel_size (root, rel, rte); / / regular datasheet} break Case RTE_SUBQUERY:// subquery / * * Subqueries don't support making a choice between * parameterized and unparameterized paths, so just go ahead * and build their paths immediately. * / set_subquery_pathlist (root, rel, rti, rte); / / generate sub-query access path break; case RTE_FUNCTION://FUNCTION set_function_size_estimates (root, rel); break; case RTE_TABLEFUNC://TABLEFUNC set_tablefunc_size_estimates (root, rel) Break; case RTE_VALUES://VALUES set_values_size_estimates (root, rel); break Case RTE_CTE://CTE / * * CTEs don't support making a choice between parameterized * and unparameterized paths, so just go ahead and build their * paths immediately. * / if (rte- > self_reference) set_worktable_pathlist (root, rel, rte); else set_cte_pathlist (root, rel, rte); break; case RTE_NAMEDTUPLESTORE://NAMEDTUPLESTORE, named tuple storage set_namedtuplestore_pathlist (root, rel, rte) Break; default: elog (ERROR, "unexpected rtekind:% d", (int) rel- > rtekind); break;}} / * * We insist that all non-dummy rels have a nonzero rowcount estimate. * / Assert (rel- > rows > 0 | | IS_DUMMY_REL (rel));} / /-- / * * set_base_rel_pathlists * Finds all paths available for scanning each base-relation entry. * Sequential scan and any available indices are considered. * Each useful path is attached to its relation's' pathlist' field. * * find all available access paths for each base rels (sequential scans and all available indexes are taken into account) * every available path is added to the pathlist linked list * * / static void set_base_rel_pathlists (PlannerInfo * root) {Index rti; for (rti = 1; rti)
< root->