costsize.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,993 行 · 第 1/5 页
C
1,993 行
{ /* assume we need 50% of the tuples */ total->per_tuple += 0.50 * plan_run_cost; /* also charge a cpu_operator_cost per row examined */ total->per_tuple += 0.50 * plan->plan_rows * cpu_operator_cost; } else { /* assume we need all tuples */ total->per_tuple += plan_run_cost; } /* * Also account for subplan's startup cost. If the subplan is * uncorrelated or undirect correlated, AND its topmost node * is a Sort or Material node, assume that we'll only need to * pay its startup cost once; otherwise assume we pay the * startup cost every time. */ if (subplan->parParam == NIL && (IsA(plan, Sort) || IsA(plan, Material))) total->startup += plan->startup_cost; else total->per_tuple += plan->startup_cost; } } return expression_tree_walker(node, cost_qual_eval_walker, (void *) total);}/* * approx_selectivity * Quick-and-dirty estimation of clause selectivities. * The input can be either an implicitly-ANDed list of boolean * expressions, or a list of RestrictInfo nodes (typically the latter). * * The "quick" part comes from caching the selectivity estimates so we can * avoid recomputing them later. (Since the same clauses are typically * examined over and over in different possible join trees, this makes a * big difference.) * * The "dirty" part comes from the fact that the selectivities of multiple * clauses are estimated independently and multiplied together. Now * clauselist_selectivity often can't do any better than that anyhow, but * for some situations (such as range constraints) it is smarter. * * Since we are only using the results to estimate how many potential * output tuples are generated and passed through qpqual checking, it * seems OK to live with the approximation. */static Selectivityapprox_selectivity(Query *root, List *quals, JoinType jointype){ Selectivity total = 1.0; List *l; foreach(l, quals) { Node *qual = (Node *) lfirst(l); Selectivity selec; /* * RestrictInfo nodes contain a this_selec field reserved for this * routine's use, so that it's not necessary to evaluate the qual * clause's selectivity more than once. If the clause's * selectivity hasn't been computed yet, the field will contain * -1. */ if (qual && IsA(qual, RestrictInfo)) { RestrictInfo *restrictinfo = (RestrictInfo *) qual; if (restrictinfo->this_selec < 0) restrictinfo->this_selec = clause_selectivity(root, (Node *) restrictinfo->clause, 0, jointype); selec = restrictinfo->this_selec; } else { /* If it's a bare expression, must always do it the hard way */ selec = clause_selectivity(root, qual, 0, jointype); } total *= selec; } return total;}/* * set_baserel_size_estimates * Set the size estimates for the given base relation. * * The rel's targetlist and restrictinfo list must have been constructed * already. * * We set the following fields of the rel node: * rows: the estimated number of output tuples (after applying * restriction clauses). * width: the estimated average output tuple width in bytes. * baserestrictcost: estimated cost of evaluating baserestrictinfo clauses. */voidset_baserel_size_estimates(Query *root, RelOptInfo *rel){ double temp; /* Should only be applied to base relations */ Assert(rel->relid > 0); temp = rel->tuples * restrictlist_selectivity(root, rel->baserestrictinfo, rel->relid, JOIN_INNER); /* * Force estimate to be at least one row, to make explain output look * better and to avoid possible divide-by-zero when interpolating * cost. Make it an integer, too. */ if (temp < 1.0) temp = 1.0; else temp = ceil(temp); rel->rows = temp; cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo); set_rel_width(root, rel);}/* * set_joinrel_size_estimates * Set the size estimates for the given join relation. * * The rel's targetlist must have been constructed already, and a * restriction clause list that matches the given component rels must * be provided. * * Since there is more than one way to make a joinrel for more than two * base relations, the results we get here could depend on which component * rel pair is provided. In theory we should get the same answers no matter * which pair is provided; in practice, since the selectivity estimation * routines don't handle all cases equally well, we might not. But there's * not much to be done about it. (Would it make sense to repeat the * calculations for each pair of input rels that's encountered, and somehow * average the results? Probably way more trouble than it's worth.) * * It's important that the results for symmetric JoinTypes be symmetric, * eg, (rel1, rel2, JOIN_LEFT) should produce the same result as (rel2, * rel1, JOIN_RIGHT). Also, JOIN_IN should produce the same result as * JOIN_UNIQUE_INNER, likewise JOIN_REVERSE_IN == JOIN_UNIQUE_OUTER. * * We set the same relnode fields as set_baserel_size_estimates() does. */voidset_joinrel_size_estimates(Query *root, RelOptInfo *rel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype, List *restrictlist){ Selectivity selec; double temp; UniquePath *upath; /* * Compute joinclause selectivity. Note that we are only considering * clauses that become restriction clauses at this join level; we are * not double-counting them because they were not considered in * estimating the sizes of the component rels. */ selec = restrictlist_selectivity(root, restrictlist, 0, jointype); /* * Basically, we multiply size of Cartesian product by selectivity. * * If we are doing an outer join, take that into account: the output must * be at least as large as the non-nullable input. (Is there any * chance of being even smarter?) * * For JOIN_IN and variants, the Cartesian product is figured with * respect to a unique-ified input, and then we can clamp to the size * of the other input. */ switch (jointype) { case JOIN_INNER: temp = outer_rel->rows * inner_rel->rows * selec; break; case JOIN_LEFT: temp = outer_rel->rows * inner_rel->rows * selec; if (temp < outer_rel->rows) temp = outer_rel->rows; break; case JOIN_RIGHT: temp = outer_rel->rows * inner_rel->rows * selec; if (temp < inner_rel->rows) temp = inner_rel->rows; break; case JOIN_FULL: temp = outer_rel->rows * inner_rel->rows * selec; if (temp < outer_rel->rows) temp = outer_rel->rows; if (temp < inner_rel->rows) temp = inner_rel->rows; break; case JOIN_IN: case JOIN_UNIQUE_INNER: upath = create_unique_path(root, inner_rel, inner_rel->cheapest_total_path); temp = outer_rel->rows * upath->rows * selec; if (temp > outer_rel->rows) temp = outer_rel->rows; break; case JOIN_REVERSE_IN: case JOIN_UNIQUE_OUTER: upath = create_unique_path(root, outer_rel, outer_rel->cheapest_total_path); temp = upath->rows * inner_rel->rows * selec; if (temp > inner_rel->rows) temp = inner_rel->rows; break; default: elog(ERROR, "unrecognized join type: %d", (int) jointype); temp = 0; /* keep compiler quiet */ break; } /* * Force estimate to be at least one row, to make explain output look * better and to avoid possible divide-by-zero when interpolating * cost. Make it an integer, too. */ if (temp < 1.0) temp = 1.0; else temp = ceil(temp); rel->rows = temp; /* * We need not compute the output width here, because * build_joinrel_tlist already did. */}/* * set_function_size_estimates * Set the size estimates for a base relation that is a function call. * * The rel's targetlist and restrictinfo list must have been constructed * already. * * We set the following fields of the rel node: * rows: the estimated number of output tuples (after applying * restriction clauses). * width: the estimated average output tuple width in bytes. * baserestrictcost: estimated cost of evaluating baserestrictinfo clauses. */voidset_function_size_estimates(Query *root, RelOptInfo *rel){ double temp; /* Should only be applied to base relations that are functions */ Assert(rel->relid > 0); Assert(rel->rtekind == RTE_FUNCTION); /* * Estimate number of rows the function itself will return. * * XXX no idea how to do this yet; but should at least check whether * function returns set or not... */ rel->tuples = 1000; /* Now estimate number of output rows */ temp = rel->tuples * restrictlist_selectivity(root, rel->baserestrictinfo, rel->relid, JOIN_INNER); /* * Force estimate to be at least one row, to make explain output look * better and to avoid possible divide-by-zero when interpolating * cost. Make it an integer, too. */ if (temp < 1.0) temp = 1.0; else temp = ceil(temp); rel->rows = temp; cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo); set_rel_width(root, rel);}/* * set_rel_width * Set the estimated output width of a base relation. * * NB: this works best on plain relations because it prefers to look at * real Vars. It will fail to make use of pg_statistic info when applied * to a subquery relation, even if the subquery outputs are simple vars * that we could have gotten info for. Is it worth trying to be smarter * about subqueries? * * The per-attribute width estimates are cached for possible re-use while * building join relations. */static voidset_rel_width(Query *root, RelOptInfo *rel){ int32 tuple_width = 0; List *tllist; foreach(tllist, FastListValue(&rel->reltargetlist)) { Var *var = (Var *) lfirst(tllist); int ndx = var->varattno - rel->min_attr; Oid relid; int32 item_width; Assert(IsA(var, Var)); /* * The width probably hasn't been cached yet, but may as well * check */ if (rel->attr_widths[ndx] > 0) { tuple_width += rel->attr_widths[ndx]; continue; } relid = getrelid(var->varno, root->rtable); if (relid != InvalidOid) { item_width = get_attavgwidth(relid, var->varattno); if (item_width > 0) { rel->attr_widths[ndx] = item_width; tuple_width += item_width; continue; } } /* * Not a plain relation, or can't find statistics for it. Estimate * using just the type info. */ item_width = get_typavgwidth(var->vartype, var->vartypmod); Assert(item_width > 0); rel->attr_widths[ndx] = item_width; tuple_width += item_width; } Assert(tuple_width >= 0); rel->width = tuple_width;}/* * relation_byte_size * Estimate the storage space in bytes for a given number of tuples * of a given width (size in bytes). */static doublerelation_byte_size(double tuples, int width){ return tuples * (MAXALIGN(width) + MAXALIGN(sizeof(HeapTupleData)));}/* * page_size * Returns an estimate of the number of pages covered by a given * number of tuples of a given width (size in bytes). */static doublepage_size(double tuples, int width){ return ceil(relation_byte_size(tuples, width) / BLCKSZ);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?