allpaths.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,027 行 · 第 1/2 页
C
1,027 行
/*------------------------------------------------------------------------- * * allpaths.c * Routines to find possible search paths for processing a query * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.108.2.1 2003/12/17 17:08:06 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#ifdef OPTIMIZER_DEBUG#include "nodes/print.h"#endif#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/geqo.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "optimizer/plancat.h"#include "optimizer/planner.h"#include "optimizer/prep.h"#include "optimizer/var.h"#include "parser/parsetree.h"#include "parser/parse_clause.h"#include "rewrite/rewriteManip.h"/* These parameters are set by GUC */bool enable_geqo = false; /* just in case GUC doesn't set it */int geqo_threshold;static void set_base_rel_pathlists(Query *root);static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte);static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte, List *inheritlist);static void set_subquery_pathlist(Query *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte);static void set_function_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte);static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels);static bool subquery_is_pushdown_safe(Query *subquery, Query *topquery, bool *differentTypes);static bool recurse_pushdown_safe(Node *setOp, Query *topquery, bool *differentTypes);static void compare_tlist_datatypes(List *tlist, List *colTypes, bool *differentTypes);static bool qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, bool *differentTypes);static void subquery_push_qual(Query *subquery, Index rti, Node *qual);static void recurse_push_qual(Node *setOp, Query *topquery, Index rti, Node *qual);/* * make_one_rel * Finds all possible access paths for executing a query, returning a * single rel that represents the join of all base rels in the query. */RelOptInfo *make_one_rel(Query *root){ RelOptInfo *rel; /* * Generate access paths for the base rels. */ set_base_rel_pathlists(root); /* * Generate access paths for the entire join tree. */ Assert(root->jointree != NULL && IsA(root->jointree, FromExpr)); rel = make_fromexpr_rel(root, root->jointree); /* * The result should join all the query's base rels. */ Assert(bms_num_members(rel->relids) == length(root->base_rel_list)); return 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. */static voidset_base_rel_pathlists(Query *root){ List *rellist; foreach(rellist, root->base_rel_list) { RelOptInfo *rel = (RelOptInfo *) lfirst(rellist); Index rti = rel->relid; RangeTblEntry *rte; List *inheritlist; Assert(rti > 0); /* better be base rel */ rte = rt_fetch(rti, root->rtable); if (rel->rtekind == RTE_SUBQUERY) { /* Subquery --- generate a separate plan for it */ set_subquery_pathlist(root, rel, rti, rte); } else if (rel->rtekind == RTE_FUNCTION) { /* RangeFunction --- generate a separate plan for it */ set_function_pathlist(root, rel, rte); } else if ((inheritlist = expand_inherited_rtentry(root, rti, true)) != NIL) { /* Relation is root of an inheritance tree, process specially */ set_inherited_rel_pathlist(root, rel, rti, rte, inheritlist); } else { /* Plain relation */ set_plain_rel_pathlist(root, rel, rte); }#ifdef OPTIMIZER_DEBUG debug_print_rel(root, rel);#endif }}/* * set_plain_rel_pathlist * Build access paths for a plain relation (no subquery, no inheritance) */static voidset_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte){ /* Mark rel with estimated output rows, width, etc */ set_baserel_size_estimates(root, rel); /* * Generate paths and add them to the rel's pathlist. * * Note: add_path() will discard any paths that are dominated by another * available path, keeping only those paths that are superior along at * least one dimension of cost or sortedness. */ /* Consider sequential scan */ add_path(rel, create_seqscan_path(root, rel)); /* Consider TID scans */ create_tidscan_paths(root, rel); /* Consider index paths for both simple and OR index clauses */ create_index_paths(root, rel); /* create_index_paths must be done before create_or_index_paths */ create_or_index_paths(root, rel); /* Now find the cheapest of the paths for this rel */ set_cheapest(rel);}/* * set_inherited_rel_pathlist * Build access paths for a inheritance tree rooted at rel * * inheritlist is a list of RT indexes of all tables in the inheritance tree, * including a duplicate of the parent itself. Note we will not come here * unless there's at least one child in addition to the parent. * * NOTE: the passed-in rel and RTE will henceforth represent the appended * result of the whole inheritance tree. The members of inheritlist represent * the individual tables --- in particular, the inheritlist member that is a * duplicate of the parent RTE represents the parent table alone. * We will generate plans to scan the individual tables that refer to * the inheritlist RTEs, whereas Vars elsewhere in the plan tree that * refer to the original RTE are taken to refer to the append output. * In particular, this means we have separate RelOptInfos for the parent * table and for the append output, which is a good thing because they're * not the same size. */static voidset_inherited_rel_pathlist(Query *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte, List *inheritlist){ int parentRTindex = rti; Oid parentOID = rte->relid; List *subpaths = NIL; List *il; /* * XXX for now, can't handle inherited expansion of FOR UPDATE; can we * do better? */ if (intMember(parentRTindex, root->rowMarks)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SELECT FOR UPDATE is not supported for inheritance queries"))); /* * The executor will check the parent table's access permissions when * it examines the parent's inheritlist entry. There's no need to * check twice, so turn off access check bits in the original RTE. */ rte->checkForRead = false; rte->checkForWrite = false; /* * Initialize to compute size estimates for whole inheritance tree */ rel->rows = 0; rel->width = 0; /* * Generate access paths for each table in the tree (parent AND * children), and pick the cheapest path for each table. */ foreach(il, inheritlist) { int childRTindex = lfirsti(il); RangeTblEntry *childrte; Oid childOID; RelOptInfo *childrel; List *reltlist; List *parentvars; List *childvars; childrte = rt_fetch(childRTindex, root->rtable); childOID = childrte->relid; /* * Make a RelOptInfo for the child so we can do planning. Do NOT * attach the RelOptInfo to the query's base_rel_list, however, * since the child is not part of the main join tree. Instead, * the child RelOptInfo is added to other_rel_list. */ childrel = build_other_rel(root, childRTindex); /* * Copy the parent's targetlist and restriction quals to the * child, with attribute-number adjustment as needed. We don't * bother to copy the join quals, since we can't do any joining of * the individual tables. Also, we just zap attr_needed rather * than trying to adjust it; it won't be looked at in the child. */ reltlist = FastListValue(&rel->reltargetlist); reltlist = (List *) adjust_inherited_attrs((Node *) reltlist, parentRTindex, parentOID, childRTindex, childOID); FastListFromList(&childrel->reltargetlist, reltlist); childrel->attr_needed = NULL; childrel->baserestrictinfo = (List *) adjust_inherited_attrs((Node *) rel->baserestrictinfo, parentRTindex, parentOID, childRTindex, childOID); /* * Now compute child access paths, and save the cheapest. */ set_plain_rel_pathlist(root, childrel, childrte); subpaths = lappend(subpaths, childrel->cheapest_total_path); /* * Propagate size information from the child back to the parent. * For simplicity, we use the largest widths from any child as the * parent estimates. */ rel->rows += childrel->rows; if (childrel->width > rel->width) rel->width = childrel->width; childvars = FastListValue(&childrel->reltargetlist); foreach(parentvars, FastListValue(&rel->reltargetlist)) { Var *parentvar = (Var *) lfirst(parentvars); Var *childvar = (Var *) lfirst(childvars); int parentndx = parentvar->varattno - rel->min_attr; int childndx = childvar->varattno - childrel->min_attr; if (childrel->attr_widths[childndx] > rel->attr_widths[parentndx]) rel->attr_widths[parentndx] = childrel->attr_widths[childndx]; childvars = lnext(childvars); } } /* * Finally, build Append path and install it as the only access path * for the parent rel. */ add_path(rel, (Path *) create_append_path(rel, subpaths)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel);}/* * set_subquery_pathlist * Build the (single) access path for a subquery RTE */static voidset_subquery_pathlist(Query *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte){ Query *subquery = rte->subquery; bool *differentTypes; List *pathkeys; /* We need a workspace for keeping track of set-op type coercions */ differentTypes = (bool *) palloc0((length(subquery->targetList) + 1) * sizeof(bool)); /* * If there are any restriction clauses that have been attached to the * subquery relation, consider pushing them down to become HAVING * quals of the subquery itself. (Not WHERE clauses, since they may * refer to subquery outputs that are aggregate results. But * planner.c will transfer them into the subquery's WHERE if they do * not.) This transformation is useful because it may allow us to * generate a better plan for the subquery than evaluating all the * subquery output rows and then filtering them. * * There are several cases where we cannot push down clauses. * Restrictions involving the subquery are checked by * subquery_is_pushdown_safe(). Restrictions on individual clauses * are checked by qual_is_pushdown_safe(). * * Non-pushed-down clauses will get evaluated as qpquals of the * SubqueryScan node. * * XXX Are there any cases where we want to make a policy decision not to * push down a pushable qual, because it'd result in a worse plan? */ if (rel->baserestrictinfo != NIL && subquery_is_pushdown_safe(subquery, subquery, differentTypes)) { /* OK to consider pushing down individual quals */ List *upperrestrictlist = NIL; List *lst; foreach(lst, rel->baserestrictinfo) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(lst); Node *clause = (Node *) rinfo->clause; if (qual_is_pushdown_safe(subquery, rti, clause, differentTypes)) { /* Push it down */ subquery_push_qual(subquery, rti, clause); } else { /* Keep it in the upper query */ upperrestrictlist = lappend(upperrestrictlist, rinfo); } } rel->baserestrictinfo = upperrestrictlist; } pfree(differentTypes); /* Generate the plan for the subquery */ rel->subplan = subquery_planner(subquery, 0.0 /* default case */ ); /* Copy number of output rows from subplan */ rel->tuples = rel->subplan->plan_rows; /* Mark rel with estimated output rows, width, etc */ set_baserel_size_estimates(root, rel); /* Convert subquery pathkeys to outer representation */ pathkeys = build_subquery_pathkeys(root, rel, subquery); /* Generate appropriate path */ add_path(rel, create_subqueryscan_path(rel, pathkeys)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel);}/* * set_function_pathlist * Build the (single) access path for a function RTE */static voidset_function_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte){ /* Mark rel with estimated output rows, width, etc */ set_function_size_estimates(root, rel); /* Generate appropriate path */ add_path(rel, create_functionscan_path(root, rel)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel);}/* * make_fromexpr_rel * Build access paths for a FromExpr jointree node. */RelOptInfo *make_fromexpr_rel(Query *root, FromExpr *from){ int levels_needed; List *initial_rels = NIL; List *jt; /* * Count the number of child jointree nodes. This is the depth of the * dynamic-programming algorithm we must employ to consider all ways * of joining the child nodes. */ levels_needed = length(from->fromlist); if (levels_needed <= 0) return NULL; /* nothing to do? */ /* * Construct a list of rels corresponding to the child jointree nodes. * This may contain both base rels and rels constructed according to * explicit JOIN directives. */ foreach(jt, from->fromlist) { Node *jtnode = (Node *) lfirst(jt); initial_rels = lappend(initial_rels, make_jointree_rel(root, jtnode)); } if (levels_needed == 1) { /* * Single jointree node, so we're done. */ return (RelOptInfo *) lfirst(initial_rels); } else { /* * Consider the different orders in which we could join the rels, * using either GEQO or regular optimizer. */ if (enable_geqo && levels_needed >= geqo_threshold) return geqo(root, levels_needed, initial_rels); else return make_one_rel_by_joins(root, levels_needed, initial_rels); }}/* * make_one_rel_by_joins * Find all possible joinpaths for a query by successively finding ways * to join component relations into join relations. * * 'levels_needed' is the number of iterations needed, ie, the number of * independent jointree items in the query. This is > 1. * * 'initial_rels' is a list of RelOptInfo nodes for each independent * jointree item. These are the components to be joined together. * * Returns the final level of join relations, i.e., the relation that is * the result of joining all the original relations together. */static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels){ List **joinitems; int lev; RelOptInfo *rel; /* * We employ a simple "dynamic programming" algorithm: we first find * all ways to build joins of two jointree items, then all ways to * build joins of three items (from two-item joins and single items), * then four-item joins, and so on until we have considered all ways * to join all the items into one rel. * * joinitems[j] is a list of all the j-item rels. Initially we set * joinitems[1] to represent all the single-jointree-item relations. */ joinitems = (List **) palloc0((levels_needed + 1) * sizeof(List *)); joinitems[1] = initial_rels; for (lev = 2; lev <= levels_needed; lev++) { List *x; /* * Determine all possible pairs of relations to be joined at this * level, and build paths for making each one from every available
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?