📄 createplan.c
字号:
/* Process the bitmapqual tree into a Plan tree and qual lists */ bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual, &bitmapqualorig, &indexquals); /* Reduce RestrictInfo list to bare expressions */ scan_clauses = get_actual_clauses(scan_clauses); /* * If this is a innerjoin scan, the indexclauses will contain join clauses * that are not present in scan_clauses (since the passed-in value is just * the rel's baserestrictinfo list). We must add these clauses to * scan_clauses to ensure they get checked. In most cases we will remove * the join clauses again below, but if a join clause contains a special * operator, we need to make sure it gets into the scan_clauses. */ if (best_path->isjoininner) { scan_clauses = list_concat_unique(scan_clauses, bitmapqualorig); } /* * The qpqual list must contain all restrictions not automatically handled * by the index. All the predicates in the indexquals will be checked * (either by the index itself, or by nodeBitmapHeapscan.c), but if there * are any "special" or lossy operators involved then they must be added * to qpqual. The upshot is that qpqual must contain scan_clauses minus * whatever appears in indexquals. * * In normal cases simple equal() checks will be enough to spot duplicate * clauses, so we try that first. In some situations (particularly with * OR'd index conditions) we may have scan_clauses that are not equal to, * but are logically implied by, the index quals; so we also try a * predicate_implied_by() check to see if we can discard quals that way. * (predicate_implied_by assumes its first input contains only immutable * functions, so we have to check that.) * * Unlike create_indexscan_plan(), we need take no special thought here * for partial index predicates; this is because the predicate conditions * are already listed in bitmapqualorig and indexquals. Bitmap scans * have to do it that way because predicate conditions need to be rechecked * if the scan becomes lossy. */ qpqual = NIL; foreach(l, scan_clauses) { Node *clause = (Node *) lfirst(l); if (list_member(indexquals, clause)) continue; if (!contain_mutable_functions(clause)) { List *clausel = list_make1(clause); if (predicate_implied_by(clausel, indexquals)) continue; } qpqual = lappend(qpqual, clause); } /* Sort clauses into best execution order */ qpqual = order_qual_clauses(root, qpqual); /* * When dealing with special or lossy operators, we will at this point * have duplicate clauses in qpqual and bitmapqualorig. We may as well * drop 'em from bitmapqualorig, since there's no point in making the * tests twice. */ bitmapqualorig = list_difference_ptr(bitmapqualorig, qpqual); /* * Copy the finished bitmapqualorig to make sure we have an independent * copy --- needed in case there are subplans in the index quals */ bitmapqualorig = copyObject(bitmapqualorig); /* Finally ready to build the plan node */ scan_plan = make_bitmap_heapscan(tlist, qpqual, bitmapqualplan, bitmapqualorig, baserelid); copy_path_costsize(&scan_plan->scan.plan, &best_path->path); /* use the indexscan-specific rows estimate, not the parent rel's */ scan_plan->scan.plan.plan_rows = best_path->rows; return scan_plan;}/* * Given a bitmapqual tree, generate the Plan tree that implements it * * As byproducts, we also return in *qual and *indexqual the qual lists * (in implicit-AND form, without RestrictInfos) describing the original index * conditions and the generated indexqual conditions. The latter is made to * exclude lossy index operators. Both lists include partial-index predicates, * because we have to recheck predicates as well as index conditions if the * bitmap scan becomes lossy. * * Note: if you find yourself changing this, you probably need to change * make_restrictinfo_from_bitmapqual too. */static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, List **qual, List **indexqual){ Plan *plan; if (IsA(bitmapqual, BitmapAndPath)) { BitmapAndPath *apath = (BitmapAndPath *) bitmapqual; List *subplans = NIL; List *subquals = NIL; List *subindexquals = NIL; ListCell *l; /* * There may well be redundant quals among the subplans, since a * top-level WHERE qual might have gotten used to form several * different index quals. We don't try exceedingly hard to eliminate * redundancies, but we do eliminate obvious duplicates by using * list_concat_unique. */ foreach(l, apath->bitmapquals) { Plan *subplan; List *subqual; List *subindexqual; subplan = create_bitmap_subplan(root, (Path *) lfirst(l), &subqual, &subindexqual); subplans = lappend(subplans, subplan); subquals = list_concat_unique(subquals, subqual); subindexquals = list_concat_unique(subindexquals, subindexqual); } plan = (Plan *) make_bitmap_and(subplans); plan->startup_cost = apath->path.startup_cost; plan->total_cost = apath->path.total_cost; plan->plan_rows = clamp_row_est(apath->bitmapselectivity * apath->path.parent->tuples); plan->plan_width = 0; /* meaningless */ *qual = subquals; *indexqual = subindexquals; } else if (IsA(bitmapqual, BitmapOrPath)) { BitmapOrPath *opath = (BitmapOrPath *) bitmapqual; List *subplans = NIL; List *subquals = NIL; List *subindexquals = NIL; bool const_true_subqual = false; bool const_true_subindexqual = false; ListCell *l; /* * Here, we only detect qual-free subplans. A qual-free subplan would * cause us to generate "... OR true ..." which we may as well reduce * to just "true". We do not try to eliminate redundant subclauses * because (a) it's not as likely as in the AND case, and (b) we might * well be working with hundreds or even thousands of OR conditions, * perhaps from a long IN list. The performance of list_append_unique * would be unacceptable. */ foreach(l, opath->bitmapquals) { Plan *subplan; List *subqual; List *subindexqual; subplan = create_bitmap_subplan(root, (Path *) lfirst(l), &subqual, &subindexqual); subplans = lappend(subplans, subplan); if (subqual == NIL) const_true_subqual = true; else if (!const_true_subqual) subquals = lappend(subquals, make_ands_explicit(subqual)); if (subindexqual == NIL) const_true_subindexqual = true; else if (!const_true_subindexqual) subindexquals = lappend(subindexquals, make_ands_explicit(subindexqual)); } plan = (Plan *) make_bitmap_or(subplans); plan->startup_cost = opath->path.startup_cost; plan->total_cost = opath->path.total_cost; plan->plan_rows = clamp_row_est(opath->bitmapselectivity * opath->path.parent->tuples); plan->plan_width = 0; /* meaningless */ /* * If there were constant-TRUE subquals, the OR reduces to constant * TRUE. Also, avoid generating one-element ORs, which could happen * due to redundancy elimination. */ if (const_true_subqual) *qual = NIL; else if (list_length(subquals) <= 1) *qual = subquals; else *qual = list_make1(make_orclause(subquals)); if (const_true_subindexqual) *indexqual = NIL; else if (list_length(subindexquals) <= 1) *indexqual = subindexquals; else *indexqual = list_make1(make_orclause(subindexquals)); } else if (IsA(bitmapqual, IndexPath)) { IndexPath *ipath = (IndexPath *) bitmapqual; IndexScan *iscan; List *nonlossy_clauses; ListCell *l; /* Use the regular indexscan plan build machinery... */ iscan = create_indexscan_plan(root, ipath, NIL, NIL, &nonlossy_clauses); /* then convert to a bitmap indexscan */ plan = (Plan *) make_bitmap_indexscan(iscan->scan.scanrelid, iscan->indexid, iscan->indexqual, iscan->indexqualorig, iscan->indexstrategy, iscan->indexsubtype); plan->startup_cost = 0.0; plan->total_cost = ipath->indextotalcost; plan->plan_rows = clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples); plan->plan_width = 0; /* meaningless */ *qual = get_actual_clauses(ipath->indexclauses); *indexqual = get_actual_clauses(nonlossy_clauses); foreach(l, ipath->indexinfo->indpred) { Expr *pred = (Expr *) lfirst(l); /* * We know that the index predicate must have been implied by * the query condition as a whole, but it may or may not be * implied by the conditions that got pushed into the * bitmapqual. Avoid generating redundant conditions. */ if (!predicate_implied_by(list_make1(pred), ipath->indexclauses)) { *qual = lappend(*qual, pred); *indexqual = lappend(*indexqual, pred); } } } else { elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual)); plan = NULL; /* keep compiler quiet */ } return plan;}/* * create_tidscan_plan * Returns a tidscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path, List *tlist, List *scan_clauses){ TidScan *scan_plan; Index scan_relid = best_path->path.parent->relid; /* it should be a base rel... */ Assert(scan_relid > 0); Assert(best_path->path.parent->rtekind == RTE_RELATION); /* Reduce RestrictInfo list to bare expressions */ scan_clauses = get_actual_clauses(scan_clauses); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); scan_plan = make_tidscan(tlist, scan_clauses, scan_relid, best_path->tideval); copy_path_costsize(&scan_plan->scan.plan, &best_path->path); return scan_plan;}/* * create_subqueryscan_plan * Returns a subqueryscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root, Path *best_path, List *tlist, List *scan_clauses){ SubqueryScan *scan_plan; Index scan_relid = best_path->parent->relid; /* it should be a subquery base rel... */ Assert(scan_relid > 0); Assert(best_path->parent->rtekind == RTE_SUBQUERY); /* Reduce RestrictInfo list to bare expressions */ scan_clauses = get_actual_clauses(scan_clauses); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); scan_plan = make_subqueryscan(tlist, scan_clauses, scan_relid, best_path->parent->subplan); copy_path_costsize(&scan_plan->scan.plan, best_path); return scan_plan;}/* * create_functionscan_plan * Returns a functionscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */static FunctionScan *create_functionscan_plan(PlannerInfo *root, Path *best_path, List *tlist, List *scan_clauses){ FunctionScan *scan_plan; Index scan_relid = best_path->parent->relid; /* it should be a function base rel... */ Assert(scan_relid > 0); Assert(best_path->parent->rtekind == RTE_FUNCTION); /* Reduce RestrictInfo list to bare expressions */ scan_clauses = get_actual_clauses(scan_clauses); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); scan_plan = make_functionscan(tlist, scan_clauses, scan_relid); copy_path_costsize(&scan_plan->scan.plan, best_path); return scan_plan;}/***************************************************************************** * * JOIN METHODS * *****************************************************************************/static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path, Plan *outer_plan, Plan *inner_plan){ List *tlist = build_relation_tlist(best_path->path.parent); List *joinrestrictclauses = best_path->joinrestrictinfo; List *joinclauses; List *otherclauses; NestLoop *join_plan; if (IsA(best_path->innerjoinpath, IndexPath)) { /* * An index is being used to reduce the number of tuples scanned in * the inner relation. If there are join clauses being used with the * index, we may remove those join clauses from the list of clauses * that have to be checked as qpquals at the join node. * * We can also remove any join clauses that are redundant with those * being used in the index scan; prior redundancy checks will not have * caught this case because the join clauses would never have been put * in the same joininfo list. * * We can skip this if the index path is an ordinary indexpath and not * a special innerjoin path. */ IndexPath *innerpath = (IndexPath *) best_path->innerjoinpath; if (innerpath->isjoininner) { joinrestrictclauses = select_nonredundant_join_clauses(root, joinrestrictclauses, innerpath->indexclauses, IS_OUTER_JOIN(best_path->jointype)); } } else if (IsA(best_path->innerjoinpath, BitmapHeapPath)) { /* * Same deal for bitmapped index scans. * * Note: both here and above, we ignore any implicit index * restrictions associated with the use of partial indexes. This is * OK because we're only trying to prove we can dispense with some * join quals; failing to prove that doesn't result in an incorrect * plan. It is the right way to proceed because adding more quals to * the stuff we got from the original query would just make it harder * to detect duplication. (Also, to change this we'd have to be * wary of UPDATE/DELETE/SELECT FOR UPDATE target relations; see * notes above about EvalPlanQual.) */ BitmapHeapPath *innerpath = (BitmapHeapPath *) best_path->innerjoinpath; if (innerpath->isjoininner) { List *bitmapclauses; bitmapclauses = make_restrictinfo_from_bitmapqual(innerpath->bitmapqual, true, false); joinrestrictclauses = select_nonredundant_join_clauses(root, joinrestrictclauses, bitmapclauses, IS_OUTER_JOIN(best_path->jointype)); } } /* Get the join qual clauses (in plain expression form) */ if (IS_OUTER_JOIN(best_path->jointype)) { get_actual_join_clauses(joinrestrictclauses, &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ joinclauses = get_actual_clauses(joinrestrictclauses); otherclauses = NIL; } /* Sort clauses into best execution order */ joinclauses = order_qual_clauses(root, joinclauses); otherclauses = order_qual_clauses(root, otherclauses); join_plan = make_nestloop(tlist, joinclauses,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -