1 /*-------------------------------------------------------------------------
4 * Routines to find possible search paths for processing a query
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.18 1998/08/04 00:42:07 momjian Exp $
12 *-------------------------------------------------------------------------
19 #include "nodes/pg_list.h"
20 #include "nodes/relation.h"
21 #include "nodes/primnodes.h"
23 #include "optimizer/internal.h"
25 #include "optimizer/paths.h"
26 #include "optimizer/pathnode.h"
27 #include "optimizer/clauses.h"
28 #include "optimizer/xfunc.h"
29 #include "optimizer/cost.h"
31 #include "commands/creatinh.h"
33 #include "optimizer/geqo_gene.h"
34 #include "optimizer/geqo.h"
37 bool _use_geqo_ = true;
40 bool _use_geqo_ = false;
43 int32 _use_geqo_rels_ = GEQO_RELS;
46 static void find_rel_paths(Query *root, List *rels);
47 static List *find_join_paths(Query *root, List *outer_rels, int levels_needed);
51 * Finds all possible access paths for executing a query, returning the
52 * top level list of relation entries.
54 * 'rels' is the list of single relation entries appearing in the query
57 find_paths(Query *root, List *rels)
62 * Set the number of join (not nesting) levels yet to be processed.
64 levels_needed = length(rels);
66 if (levels_needed <= 0)
70 * Find the base relation paths.
72 find_rel_paths(root, rels);
74 if (levels_needed <= 1)
78 * Unsorted single relation, no more processing is required.
86 * this means that joins or sorts are required. set selectivities
87 * of clauses that have not been set by an index.
89 set_rest_relselec(root, rels);
91 return find_join_paths(root, rels, levels_needed);
97 * Finds all paths available for scanning each relation entry in
98 * 'rels'. Sequential scan and any available indices are considered
99 * if possible(indices are not considered for lower nesting levels).
100 * All unique paths are attached to the relation's 'pathlist' field.
105 find_rel_paths(Query *root, List *rels)
112 List *sequential_scan_list;
113 List *rel_index_scan_list;
114 List *or_index_scan_list;
115 RelOptInfo *rel = (RelOptInfo *) lfirst(temp);
117 sequential_scan_list = lcons(create_seqscan_path(rel),
120 rel_index_scan_list =
121 find_index_paths(root,
123 find_relation_indices(root, rel),
127 or_index_scan_list = create_or_index_paths(root, rel, rel->clauseinfo);
129 rel->pathlist = add_pathlist(rel,
130 sequential_scan_list,
131 append(rel_index_scan_list,
132 or_index_scan_list));
135 * The unordered path is always the last in the list. If it is not
136 * the cheapest path, prune it.
138 lastpath = rel->pathlist;
139 while (lnext(lastpath) != NIL)
140 lastpath = lnext(lastpath);
141 prune_rel_path(rel, (Path *) lfirst(lastpath));
144 * if there is a qualification of sequential scan the selec. value
145 * is not set -- so set it explicitly -- Sunita
147 set_rest_selec(root, rel->clauseinfo);
148 rel->size = compute_rel_size(rel);
149 rel->width = compute_rel_width(rel);
156 * Find all possible joinpaths for a query by successively finding ways
157 * to join single relations into join relations.
159 * if BushyPlanFlag is set, bushy tree plans will be generated:
160 * Find all possible joinpaths(bushy trees) for a query by systematically
161 * finding ways to join relations(both original and derived) together.
163 * 'outer-rels' is the current list of relations for which join paths
164 * are to be found, i.e., he current list of relations that
165 * have already been derived.
166 * 'levels-needed' is the number of iterations needed
168 * Returns the final level of join relations, i.e., the relation that is
169 * the result of joining all the original relations together.
172 find_join_paths(Query *root, List *outer_rels, int levels_needed)
175 List *new_rels = NIL;
178 /*******************************************
179 * genetic query optimizer entry point *
180 * <utesch@aut.tu-freiberg.de> *
181 *******************************************/
183 if ((_use_geqo_) && length(root->base_relation_list_) >= _use_geqo_rels_)
184 return lcons(geqo(root), NIL); /* returns *one* RelOptInfo, so lcons it */
186 /*******************************************
187 * rest will be deprecated in case of GEQO *
188 *******************************************/
190 while (--levels_needed)
194 * Determine all possible pairs of relations to be joined at this
195 * level. Determine paths for joining these relation pairs and
196 * modify 'new-rels' accordingly, then eliminate redundant join
199 new_rels = find_join_rels(root, outer_rels);
201 find_all_join_paths(root, new_rels);
203 prune_joinrels(new_rels);
208 * * for each expensive predicate in each path in each distinct
209 * rel, * consider doing pullup -- JMH
211 if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
213 xfunc_trypullup((RelOptInfo *) lfirst(x));
216 prune_rel_paths(new_rels);
222 * In case of bushy trees if there is still a join between a
223 * join relation and another relation, add a new joininfo that
224 * involves the join relation to the joininfo list of the
227 add_new_joininfos(root, new_rels, outer_rels);
232 rel = (RelOptInfo *) lfirst(x);
234 rel->size = compute_rel_size(rel);
235 rel->width = compute_rel_width(rel);
237 /* #define OPTIMIZER_DEBUG */
238 #ifdef OPTIMIZER_DEBUG
239 printf("levels left: %d\n", levels_left);
240 debug_print_rel(root, rel);
248 * prune rels that have been completely incorporated into new
251 outer_rels = prune_oldrels(outer_rels);
254 * merge join rels if then contain the same list of base rels
256 outer_rels = merge_joinrels(new_rels, outer_rels);
257 root->join_relation_list_ = outer_rels;
260 root->join_relation_list_ = new_rels;
262 outer_rels = new_rels;
266 return final_join_rels(outer_rels);
271 /*****************************************************************************
273 *****************************************************************************/
275 #ifdef OPTIMIZER_DEBUG
277 print_joinclauses(Query *root, List *clauses)
280 extern void print_expr(Node *expr, List *rtable); /* in print.c */
284 CInfo *c = lfirst(l);
286 print_expr((Node *) c->clause, root->rtable);
293 print_path(Query *root, Path *path, int indent)
300 for (i = 0; i < indent; i++)
303 switch (nodeTag(path))
330 int size = path->parent->size;
332 jp = (JoinPath *) path;
333 printf("%s size=%d cost=%f\n", ptype, size, path->path_cost);
334 switch (nodeTag(path))
338 for (i = 0; i < indent + 1; i++)
340 printf(" clauses=(");
341 print_joinclauses(root,
342 ((JoinPath *) path)->pathclauseinfo);
345 if (nodeTag(path) == T_MergePath)
347 MergePath *mp = (MergePath *) path;
349 if (mp->outersortkeys || mp->innersortkeys)
351 for (i = 0; i < indent + 1; i++)
353 printf(" sortouter=%d sortinner=%d\n",
354 ((mp->outersortkeys) ? 1 : 0),
355 ((mp->innersortkeys) ? 1 : 0));
362 print_path(root, jp->outerjoinpath, indent + 1);
363 print_path(root, jp->innerjoinpath, indent + 1);
367 int size = path->parent->size;
368 int relid = lfirsti(path->parent->relids);
370 printf("%s(%d) size=%d cost=%f",
371 ptype, relid, size, path->path_cost);
373 if (nodeTag(path) == T_IndexPath)
379 foreach(k, path->keys)
382 foreach(l, lfirst(k))
384 Var *var = lfirst(l);
386 printf("%d.%d", var->varnoold, var->varoattno);
400 debug_print_rel(Query *root, RelOptInfo *rel)
405 foreach(l, rel->relids)
406 printf("%d ", lfirsti(l));
407 printf("): size=%d width=%d\n", rel->size, rel->width);
409 printf("\tpath list:\n");
410 foreach(l, rel->pathlist)
411 print_path(root, lfirst(l), 1);
412 printf("\tcheapest path:\n");
413 print_path(root, rel->cheapestpath, 1);
416 #endif /* OPTIMIZER_DEBUG */