1 /*-------------------------------------------------------------------------
4 * Routines to manipulate pathlists and create path nodes
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.63 2000/04/12 17:15:24 momjian Exp $
13 *-------------------------------------------------------------------------
19 #include "optimizer/cost.h"
20 #include "optimizer/pathnode.h"
21 #include "optimizer/paths.h"
22 #include "optimizer/plancat.h"
23 #include "optimizer/restrictinfo.h"
24 #include "parser/parsetree.h"
27 /*****************************************************************************
28 * MISC. PATH UTILITIES
29 *****************************************************************************/
33 * Return -1, 0, or +1 according as path1 is cheaper, the same cost,
34 * or more expensive than path2 for the specified criterion.
37 compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
39 if (criterion == STARTUP_COST)
41 if (path1->startup_cost < path2->startup_cost)
43 if (path1->startup_cost > path2->startup_cost)
47 * If paths have the same startup cost (not at all unlikely),
48 * order them by total cost.
50 if (path1->total_cost < path2->total_cost)
52 if (path1->total_cost > path2->total_cost)
57 if (path1->total_cost < path2->total_cost)
59 if (path1->total_cost > path2->total_cost)
63 * If paths have the same total cost, order them by startup cost.
65 if (path1->startup_cost < path2->startup_cost)
67 if (path1->startup_cost > path2->startup_cost)
74 * compare_path_fractional_costs
75 * Return -1, 0, or +1 according as path1 is cheaper, the same cost,
76 * or more expensive than path2 for fetching the specified fraction
77 * of the total tuples.
79 * If fraction is <= 0 or > 1, we interpret it as 1, ie, we select the
80 * path with the cheaper total_cost.
83 compare_fractional_path_costs(Path *path1, Path *path2,
89 if (fraction <= 0.0 || fraction >= 1.0)
90 return compare_path_costs(path1, path2, TOTAL_COST);
91 cost1 = path1->startup_cost +
92 fraction * (path1->total_cost - path1->startup_cost);
93 cost2 = path2->startup_cost +
94 fraction * (path2->total_cost - path2->startup_cost);
104 * Find the minimum-cost paths from among a relation's paths,
105 * and save them in the rel's cheapest-path fields.
107 * This is normally called only after we've finished constructing the path
108 * list for the rel node.
110 * If we find two paths of identical costs, try to keep the better-sorted one.
111 * The paths might have unrelated sort orderings, in which case we can only
112 * guess which might be better to keep, but if one is superior then we
113 * definitely should keep it.
116 set_cheapest(RelOptInfo *parent_rel)
118 List *pathlist = parent_rel->pathlist;
120 Path *cheapest_startup_path;
121 Path *cheapest_total_path;
123 Assert(IsA(parent_rel, RelOptInfo));
124 Assert(pathlist != NIL);
126 cheapest_startup_path = cheapest_total_path = (Path *) lfirst(pathlist);
128 foreach(p, lnext(pathlist))
130 Path *path = (Path *) lfirst(p);
133 cmp = compare_path_costs(cheapest_startup_path, path, STARTUP_COST);
136 compare_pathkeys(cheapest_startup_path->pathkeys,
137 path->pathkeys) == PATHKEYS_BETTER2))
138 cheapest_startup_path = path;
140 cmp = compare_path_costs(cheapest_total_path, path, TOTAL_COST);
143 compare_pathkeys(cheapest_total_path->pathkeys,
144 path->pathkeys) == PATHKEYS_BETTER2))
145 cheapest_total_path = path;
148 parent_rel->cheapest_startup_path = cheapest_startup_path;
149 parent_rel->cheapest_total_path = cheapest_total_path;
154 * Consider a potential implementation path for the specified parent rel,
155 * and add it to the rel's pathlist if it is worthy of consideration.
156 * A path is worthy if it has either a better sort order (better pathkeys)
157 * or cheaper cost (on either dimension) than any of the existing old paths.
159 * Unless parent_rel->pruneable is false, we also remove from the rel's
160 * pathlist any old paths that are dominated by new_path --- that is,
161 * new_path is both cheaper and at least as well ordered.
163 * NOTE: discarded Path objects are immediately pfree'd to reduce planner
164 * memory consumption. We dare not try to free the substructure of a Path,
165 * since much of it may be shared with other Paths or the query tree itself;
166 * but just recycling discarded Path nodes is a very useful savings in
169 * 'parent_rel' is the relation entry to which the path corresponds.
170 * 'new_path' is a potential path for parent_rel.
172 * Returns nothing, but modifies parent_rel->pathlist.
175 add_path(RelOptInfo *parent_rel, Path *new_path)
177 bool accept_new = true; /* unless we find a superior old
183 * Loop to check proposed new path against old paths. Note it is
184 * possible for more than one old path to be tossed out because
185 * new_path dominates it.
187 foreach(p1, parent_rel->pathlist)
189 Path *old_path = (Path *) lfirst(p1);
190 bool remove_old = false; /* unless new proves superior */
193 costcmp = compare_path_costs(new_path, old_path, TOTAL_COST);
196 * If the two paths compare differently for startup and total
197 * cost, then we want to keep both, and we can skip the (much
198 * slower) comparison of pathkeys. If they compare the same,
199 * proceed with the pathkeys comparison. Note this test relies on
200 * the fact that compare_path_costs will only return 0 if both
201 * costs are equal (and, therefore, there's no need to call it
202 * twice in that case).
205 costcmp == compare_path_costs(new_path, old_path, STARTUP_COST))
207 switch (compare_pathkeys(new_path->pathkeys, old_path->pathkeys))
211 remove_old = true; /* new dominates old */
213 accept_new = false; /* old equals or dominates
216 case PATHKEYS_BETTER1:
218 remove_old = true; /* new dominates old */
220 case PATHKEYS_BETTER2:
222 accept_new = false; /* old dominates new */
224 case PATHKEYS_DIFFERENT:
225 /* keep both paths, since they have different ordering */
231 * Remove current element from pathlist if dominated by new,
232 * unless xfunc told us not to remove any paths.
234 if (remove_old && parent_rel->pruneable)
237 lnext(p1_prev) = lnext(p1);
239 parent_rel->pathlist = lnext(p1);
246 * If we found an old path that dominates new_path, we can quit
247 * scanning the pathlist; we will not add new_path, and we assume
248 * new_path cannot dominate any other elements of the pathlist.
256 /* Accept the path */
257 parent_rel->pathlist = lcons(new_path, parent_rel->pathlist);
261 /* Reject and recycle the path */
267 /*****************************************************************************
268 * PATH NODE CREATION ROUTINES
269 *****************************************************************************/
272 * create_seqscan_path
273 * Creates a path corresponding to a sequential scan, returning the
278 create_seqscan_path(RelOptInfo *rel)
280 Path *pathnode = makeNode(Path);
282 pathnode->pathtype = T_SeqScan;
283 pathnode->parent = rel;
284 pathnode->pathkeys = NIL; /* seqscan has unordered result */
286 cost_seqscan(pathnode, rel);
293 * Creates a path node for an index scan.
295 * 'rel' is the parent rel
296 * 'index' is an index on 'rel'
297 * 'restriction_clauses' is a list of RestrictInfo nodes
298 * to be used as index qual conditions in the scan.
299 * 'indexscandir' is ForwardScanDirection or BackwardScanDirection
300 * if the caller expects a specific scan direction,
301 * or NoMovementScanDirection if the caller is willing to accept
302 * an unordered index.
304 * Returns the new path node.
307 create_index_path(Query *root,
310 List *restriction_clauses,
311 ScanDirection indexscandir)
313 IndexPath *pathnode = makeNode(IndexPath);
316 pathnode->path.pathtype = T_IndexScan;
317 pathnode->path.parent = rel;
319 pathnode->path.pathkeys = build_index_pathkeys(root, rel, index,
321 if (pathnode->path.pathkeys == NIL)
323 /* No ordering available from index, is that OK? */
324 if (!ScanDirectionIsNoMovement(indexscandir))
325 elog(ERROR, "create_index_path: failed to create ordered index scan");
331 * The index is ordered, and build_index_pathkeys defaulted to
332 * forward scan, so make sure we mark the pathnode properly.
334 if (ScanDirectionIsNoMovement(indexscandir))
335 indexscandir = ForwardScanDirection;
338 indexquals = get_actual_clauses(restriction_clauses);
339 /* expand special operators to indexquals the executor can handle */
340 indexquals = expand_indexqual_conditions(indexquals);
343 * We are making a pathnode for a single-scan indexscan; therefore,
344 * both indexid and indexqual should be single-element lists.
346 pathnode->indexid = lconsi(index->indexoid, NIL);
347 pathnode->indexqual = lcons(indexquals, NIL);
349 pathnode->indexscandir = indexscandir;
352 * This routine is only used to generate "standalone" indexpaths, not
353 * nestloop inner indexpaths. So joinrelids is always NIL and the
354 * number of rows is the same as the parent rel's estimate.
356 pathnode->joinrelids = NIL; /* no join clauses here */
357 pathnode->rows = rel->rows;
359 cost_index(&pathnode->path, root, rel, index, indexquals, false);
365 * create_tidscan_path
366 * Creates a path corresponding to a tid_direct scan, returning the
371 create_tidscan_path(RelOptInfo *rel, List *tideval)
373 TidPath *pathnode = makeNode(TidPath);
375 pathnode->path.pathtype = T_TidScan;
376 pathnode->path.parent = rel;
377 pathnode->path.pathkeys = NIL;
378 pathnode->tideval = copyObject(tideval); /* is copy really
380 pathnode->unjoined_relids = NIL;
382 cost_tidscan(&pathnode->path, rel, tideval);
385 * divide selectivity for each clause to get an equal selectivity as
386 * IndexScan does OK ?
393 * create_nestloop_path
394 * Creates a pathnode corresponding to a nestloop join between two
397 * 'joinrel' is the join relation.
398 * 'outer_path' is the outer path
399 * 'inner_path' is the inner path
400 * 'restrict_clauses' are the RestrictInfo nodes to apply at the join
401 * 'pathkeys' are the path keys of the new join path
403 * Returns the resulting path node.
407 create_nestloop_path(RelOptInfo *joinrel,
410 List *restrict_clauses,
413 NestPath *pathnode = makeNode(NestPath);
415 pathnode->path.pathtype = T_NestLoop;
416 pathnode->path.parent = joinrel;
417 pathnode->outerjoinpath = outer_path;
418 pathnode->innerjoinpath = inner_path;
419 pathnode->joinrestrictinfo = restrict_clauses;
420 pathnode->path.pathkeys = pathkeys;
422 cost_nestloop(&pathnode->path, outer_path, inner_path, restrict_clauses);
428 * create_mergejoin_path
429 * Creates a pathnode corresponding to a mergejoin join between
432 * 'joinrel' is the join relation
433 * 'outer_path' is the outer path
434 * 'inner_path' is the inner path
435 * 'restrict_clauses' are the RestrictInfo nodes to apply at the join
436 * 'pathkeys' are the path keys of the new join path
437 * 'mergeclauses' are the RestrictInfo nodes to use as merge clauses
438 * (this should be a subset of the restrict_clauses list)
439 * 'outersortkeys' are the sort varkeys for the outer relation
440 * 'innersortkeys' are the sort varkeys for the inner relation
444 create_mergejoin_path(RelOptInfo *joinrel,
447 List *restrict_clauses,
453 MergePath *pathnode = makeNode(MergePath);
456 * If the given paths are already well enough ordered, we can skip
457 * doing an explicit sort.
460 pathkeys_contained_in(outersortkeys, outer_path->pathkeys))
463 pathkeys_contained_in(innersortkeys, inner_path->pathkeys))
466 pathnode->jpath.path.pathtype = T_MergeJoin;
467 pathnode->jpath.path.parent = joinrel;
468 pathnode->jpath.outerjoinpath = outer_path;
469 pathnode->jpath.innerjoinpath = inner_path;
470 pathnode->jpath.joinrestrictinfo = restrict_clauses;
471 pathnode->jpath.path.pathkeys = pathkeys;
472 pathnode->path_mergeclauses = mergeclauses;
473 pathnode->outersortkeys = outersortkeys;
474 pathnode->innersortkeys = innersortkeys;
476 cost_mergejoin(&pathnode->jpath.path,
487 * create_hashjoin_path
488 * Creates a pathnode corresponding to a hash join between two relations.
490 * 'joinrel' is the join relation
491 * 'outer_path' is the cheapest outer path
492 * 'inner_path' is the cheapest inner path
493 * 'restrict_clauses' are the RestrictInfo nodes to apply at the join
494 * 'hashclauses' is a list of the hash join clause (always a 1-element list)
495 * (this should be a subset of the restrict_clauses list)
496 * 'innerdisbursion' is an estimate of the disbursion of the inner hash key
500 create_hashjoin_path(RelOptInfo *joinrel,
503 List *restrict_clauses,
505 Selectivity innerdisbursion)
507 HashPath *pathnode = makeNode(HashPath);
509 pathnode->jpath.path.pathtype = T_HashJoin;
510 pathnode->jpath.path.parent = joinrel;
511 pathnode->jpath.outerjoinpath = outer_path;
512 pathnode->jpath.innerjoinpath = inner_path;
513 pathnode->jpath.joinrestrictinfo = restrict_clauses;
514 /* A hashjoin never has pathkeys, since its ordering is unpredictable */
515 pathnode->jpath.path.pathkeys = NIL;
516 pathnode->path_hashclauses = hashclauses;
518 cost_hashjoin(&pathnode->jpath.path,