geqo_eval.c 4.9 KB
Newer Older
M
Marc G. Fournier 已提交
1 2
/*------------------------------------------------------------------------
 *
3
 * geqo_eval.c
4
 *	  Routines to evaluate query trees
M
Marc G. Fournier 已提交
5
 *
B
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
7
 * Portions Copyright (c) 1994, Regents of the University of California
M
Marc G. Fournier 已提交
8
 *
9
 * $Header: /cvsroot/pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.62 2003/05/02 20:54:34 tgl Exp $
M
Marc G. Fournier 已提交
10 11 12 13 14 15
 *
 *-------------------------------------------------------------------------
 */

/* contributed by:
   =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
16 17 18
   *  Martin Utesch				 * Institute of Automatic Control	   *
   =							 = University of Mining and Technology =
   *  utesch@aut.tu-freiberg.de  * Freiberg, Germany				   *
M
Marc G. Fournier 已提交
19 20 21
   =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
 */

B
Bruce Momjian 已提交
22
#include "postgres.h"
23

24
#include <float.h>
25
#include <limits.h>
26
#include <math.h>
M
Marc G. Fournier 已提交
27 28

#include "optimizer/geqo.h"
29
#include "optimizer/pathnode.h"
B
Bruce Momjian 已提交
30
#include "optimizer/paths.h"
31
#include "utils/memutils.h"
32 33


34
/*
35
 * geqo_eval
36
 *
M
Marc G. Fournier 已提交
37 38 39
 * Returns cost of a query tree as an individual of the population.
 */
Cost
40
geqo_eval(Query *root, List *initial_rels, Gene *tour, int num_gene)
M
Marc G. Fournier 已提交
41
{
42
	MemoryContext mycontext;
B
Bruce Momjian 已提交
43 44 45 46
	MemoryContext oldcxt;
	RelOptInfo *joinrel;
	Cost		fitness;
	List	   *savelist;
47

48 49 50 51 52 53 54 55 56 57 58 59 60 61
	/*
	 * Because gimme_tree considers both left- and right-sided trees,
	 * there is no difference between a tour (a,b,c,d,...) and a tour
	 * (b,a,c,d,...) --- the same join orders will be considered.
	 * To avoid redundant cost calculations, we simply reject tours where
	 * tour[0] > tour[1], assigning them an artificially bad fitness.
	 *
	 * (It would be better to tweak the GEQO logic to not generate such tours
	 * in the first place, but I'm not sure of all the implications in the
	 * mutation logic.)
	 */
	if (num_gene >= 2 && tour[0] > tour[1])
		return DBL_MAX;

B
Bruce Momjian 已提交
62
	/*
63 64 65 66
	 * Create a private memory context that will hold all temp storage
	 * allocated inside gimme_tree().
	 *
	 * Since geqo_eval() will be called many times, we can't afford to let
B
Bruce Momjian 已提交
67
	 * all that memory go unreclaimed until end of statement.  Note we
68
	 * make the temp context a child of the planner's normal context, so that
69
	 * it will be freed even if we abort via elog(ERROR).
B
Bruce Momjian 已提交
70
	 */
71
	mycontext = AllocSetContextCreate(CurrentMemoryContext,
72 73 74 75 76 77
									  "GEQO",
									  ALLOCSET_DEFAULT_MINSIZE,
									  ALLOCSET_DEFAULT_INITSIZE,
									  ALLOCSET_DEFAULT_MAXSIZE);
	oldcxt = MemoryContextSwitchTo(mycontext);

78 79 80 81 82
	/*
	 * preserve root->join_rel_list, which gimme_tree changes; without this,
	 * it'll be pointing at recycled storage after the MemoryContextDelete
	 * below.
	 */
83
	savelist = root->join_rel_list;
M
Marc G. Fournier 已提交
84

85
	/* construct the best path for the given combination of relations */
86
	joinrel = gimme_tree(root, initial_rels, tour, num_gene);
M
Marc G. Fournier 已提交
87

88 89 90
	/*
	 * compute fitness
	 *
91 92
	 * XXX geqo does not currently support optimization for partial result
	 * retrieval --- how to fix?
93
	 */
94 95 96 97
	if (joinrel)
		fitness = joinrel->cheapest_total_path->total_cost;
	else
		fitness = DBL_MAX;
M
Marc G. Fournier 已提交
98

99 100
	/* restore join_rel_list */
	root->join_rel_list = savelist;
M
Marc G. Fournier 已提交
101

102 103
	/* release all the memory acquired within gimme_tree */
	MemoryContextSwitchTo(oldcxt);
104
	MemoryContextDelete(mycontext);
M
Marc G. Fournier 已提交
105

106
	return fitness;
M
Marc G. Fournier 已提交
107 108
}

109
/*
B
Bruce Momjian 已提交
110
 * gimme_tree
111 112
 *	  Form planner estimates for a join tree constructed in the specified
 *	  order.
113
 *
114 115 116
 *	 'root' is the Query
 *	 'initial_rels' is the list of initial relations (FROM-list items)
 *	 'tour' is the proposed join order, of length 'num_gene'
117
 *
118
 * Returns a new join relation whose cheapest path is the best plan for
119
 * this join order.  NB: will return NULL if join order is invalid.
120 121 122 123
 *
 * Note that at each step we consider using the next rel as both left and
 * right side of a join.  However, we cannot build general ("bushy") plan
 * trees this way, only left-sided and right-sided trees.
M
Marc G. Fournier 已提交
124
 */
B
Bruce Momjian 已提交
125
RelOptInfo *
126
gimme_tree(Query *root, List *initial_rels,
127
		   Gene *tour, int num_gene)
M
Marc G. Fournier 已提交
128
{
129 130 131
	RelOptInfo *joinrel;
	int			cur_rel_index;
	int			rel_count;
M
Marc G. Fournier 已提交
132

133 134 135 136 137 138 139 140 141 142 143
	/*
	 * Start with the first relation ...
	 */
	cur_rel_index = (int) tour[0];

	joinrel = (RelOptInfo *) nth(cur_rel_index - 1, initial_rels);

	/*
	 * And add on each relation in the specified order ...
	 */
	for (rel_count = 1; rel_count < num_gene; rel_count++)
144
	{
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
		RelOptInfo *inner_rel;
		RelOptInfo *new_rel;

		cur_rel_index = (int) tour[rel_count];

		inner_rel = (RelOptInfo *) nth(cur_rel_index - 1, initial_rels);

		/*
		 * Construct a RelOptInfo representing the previous joinrel joined
		 * to inner_rel.  These are always inner joins.  Note that we expect
		 * the joinrel not to exist in root->join_rel_list yet, and so the
		 * paths constructed for it will only include the ones we want.
		 */
		new_rel = make_join_rel(root, joinrel, inner_rel, JOIN_INNER);

160 161 162 163
		/* Fail if join order is not valid */
		if (new_rel == NULL)
			return NULL;

164 165 166 167 168
		/* Find and save the cheapest paths for this rel */
		set_cheapest(new_rel);

		/* and repeat... */
		joinrel = new_rel;
M
Marc G. Fournier 已提交
169 170
	}

171
	return joinrel;
M
Marc G. Fournier 已提交
172
}