1999-02-09 04:51:42 +01:00
|
|
|
Summary
|
|
|
|
-------
|
|
|
|
|
2000-02-07 05:41:04 +01:00
|
|
|
These directories take the Query structure returned by the parser, and
|
|
|
|
generate a plan used by the executor. The /plan directory generates the
|
|
|
|
actual output plan, the /path code generates all possible ways to join the
|
|
|
|
tables, and /prep handles special cases like inheritance. /util is utility
|
|
|
|
stuff. /geqo is the separate "genetic optimization" planner --- it does
|
|
|
|
a semi-random search through the join tree space, rather than exhaustively
|
|
|
|
considering all possible join trees. (But each join considered by geqo
|
|
|
|
is given to /path to create paths for, so we consider all possible
|
|
|
|
implementation paths for each specific join even in GEQO mode.)
|
|
|
|
|
|
|
|
|
|
|
|
Join Tree Construction
|
|
|
|
----------------------
|
|
|
|
|
1999-08-16 04:17:58 +02:00
|
|
|
The optimizer generates optimal query plans by doing a more-or-less
|
|
|
|
exhaustive search through the ways of executing the query. During
|
|
|
|
the planning/optimizing process, we build "Path" trees representing
|
|
|
|
the different ways of doing a query. We select the cheapest Path
|
|
|
|
that generates the desired relation and turn it into a Plan to pass
|
|
|
|
to the executor. (There is pretty much a one-to-one correspondence
|
|
|
|
between the Path and Plan trees, but Path nodes omit info that won't
|
|
|
|
be needed during planning, and include info needed for planning that
|
|
|
|
won't be needed by the executor.)
|
|
|
|
|
|
|
|
The best Path tree is found by a recursive process:
|
|
|
|
|
|
|
|
1) Take each base relation in the query, and make a RelOptInfo structure
|
|
|
|
for it. Find each potentially useful way of accessing the relation,
|
|
|
|
including sequential and index scans, and make a Path representing that
|
|
|
|
way. All the Paths made for a given relation are placed in its
|
|
|
|
RelOptInfo.pathlist. (Actually, we discard Paths that are obviously
|
|
|
|
inferior alternatives before they ever get into the pathlist --- what
|
|
|
|
ends up in the pathlist is the cheapest way of generating each potentially
|
|
|
|
useful sort ordering of the relation.) Also create RelOptInfo.joininfo
|
|
|
|
nodes that list all the joins that involve this relation. For example,
|
|
|
|
the WHERE clause "tab1.col1 = tab2.col1" generates a JoinInfo for tab1
|
|
|
|
listing tab2 as an unjoined relation, and also one for tab2 showing tab1
|
|
|
|
as an unjoined relation.
|
|
|
|
|
2000-02-07 05:41:04 +01:00
|
|
|
If we have only a single base relation in the query, we are done here.
|
|
|
|
Otherwise we have to figure out how to join the base relations into a
|
|
|
|
single join relation.
|
|
|
|
|
1999-08-16 04:17:58 +02:00
|
|
|
2) Consider joining each RelOptInfo to each other RelOptInfo specified in
|
|
|
|
its RelOptInfo.joininfo, and generate a Path for each possible join method.
|
2000-02-07 05:41:04 +01:00
|
|
|
(If we have a RelOptInfo with no join clauses, we have no choice but to
|
|
|
|
generate a clauseless Cartesian-product join; so we consider joining that
|
|
|
|
rel to each other available rel. But in the presence of join clauses we
|
|
|
|
will only consider joins that use available join clauses.)
|
|
|
|
|
1999-08-16 04:17:58 +02:00
|
|
|
At this stage each input RelOptInfo is a single relation, so we are joining
|
|
|
|
every relation to the other relations as joined in the WHERE clause. We
|
|
|
|
generate a new "join" RelOptInfo for each possible combination of two
|
|
|
|
"base" RelOptInfos, and put all the plausible paths for that combination
|
|
|
|
into the join RelOptInfo's pathlist. (As before, we keep only the cheapest
|
|
|
|
alternative that generates any one sort ordering of the result.)
|
|
|
|
|
|
|
|
Joins always occur using two RelOptInfos. One is outer, the other inner.
|
|
|
|
Outers drive lookups of values in the inner. In a nested loop, lookups of
|
|
|
|
values in the inner occur by scanning the inner path once per outer tuple
|
|
|
|
to find each matching inner row. In a mergejoin, inner and outer rows are
|
|
|
|
ordered, and are accessed in order, so only one scan is required to perform
|
|
|
|
the entire join: both inner and outer paths are scanned in-sync. (There's
|
|
|
|
not a lot of difference between inner and outer in a mergejoin...) In a
|
|
|
|
hashjoin, the inner is scanned first and all its rows are entered in a
|
|
|
|
hashtable, then the outer is scanned and for each row we lookup the join
|
|
|
|
key in the hashtable.
|
|
|
|
|
|
|
|
A Path for a join relation is actually a tree structure, with the top
|
|
|
|
Path node representing the join method. It has left and right subpaths
|
|
|
|
that represent the scan methods used for the two input relations.
|
|
|
|
|
|
|
|
3) If we only had two base relations, we are done: we just pick the
|
|
|
|
cheapest path for the join RelOptInfo. If we had more than two, we now
|
|
|
|
need to consider ways of joining join RelOptInfos to each other to make
|
2000-02-07 05:41:04 +01:00
|
|
|
join RelOptInfos that represent more than two base relations.
|
|
|
|
|
|
|
|
The join tree is constructed using a "dynamic programming" algorithm:
|
|
|
|
in the first pass (already described) we consider ways to create join rels
|
|
|
|
representing exactly two base relations. The second pass considers ways
|
|
|
|
to make join rels that represent exactly three base relations; the next pass,
|
|
|
|
four relations, etc. The last pass considers how to make the final join
|
|
|
|
relation that includes all base rels --- obviously there can be only one
|
|
|
|
join rel at this top level, whereas there can be more than one join rel
|
|
|
|
at lower levels. At each level we use joins that follow available join
|
|
|
|
clauses, if possible, just as described for the first level.
|
1999-08-16 04:17:58 +02:00
|
|
|
|
|
|
|
For example:
|
1999-02-09 04:51:42 +01:00
|
|
|
|
1999-02-15 23:19:01 +01:00
|
|
|
SELECT *
|
|
|
|
FROM tab1, tab2, tab3, tab4
|
|
|
|
WHERE tab1.col = tab2.col AND
|
|
|
|
tab2.col = tab3.col AND
|
|
|
|
tab3.col = tab4.col
|
|
|
|
|
|
|
|
Tables 1, 2, 3, and 4 are joined as:
|
|
|
|
{1 2},{2 3},{3 4}
|
|
|
|
{1 2 3},{2 3 4}
|
|
|
|
{1 2 3 4}
|
2000-02-07 05:41:04 +01:00
|
|
|
(other possibilities will be excluded for lack of join clauses)
|
1999-02-15 23:19:01 +01:00
|
|
|
|
|
|
|
SELECT *
|
|
|
|
FROM tab1, tab2, tab3, tab4
|
|
|
|
WHERE tab1.col = tab2.col AND
|
|
|
|
tab1.col = tab3.col AND
|
|
|
|
tab1.col = tab4.col
|
|
|
|
|
|
|
|
Tables 1, 2, 3, and 4 are joined as:
|
|
|
|
{1 2},{1 3},{1 4}
|
2000-02-07 05:41:04 +01:00
|
|
|
{1 2 3},{1 3 4},{1 2 4}
|
1999-02-15 23:19:01 +01:00
|
|
|
{1 2 3 4}
|
|
|
|
|
2000-02-07 05:41:04 +01:00
|
|
|
We consider left-handed plans (the outer rel of an upper join is a joinrel,
|
|
|
|
but the inner is always a base rel); right-handed plans (outer rel is always
|
|
|
|
a base rel); and bushy plans (both inner and outer can be joins themselves).
|
|
|
|
For example, when building {1 2 3 4} we consider joining {1 2 3} to {4}
|
|
|
|
(left-handed), {4} to {1 2 3} (right-handed), and {1 2} to {3 4} (bushy),
|
|
|
|
among other choices. Although the jointree scanning code produces these
|
|
|
|
potential join combinations one at a time, all the ways to produce the
|
|
|
|
same set of joined base rels will share the same RelOptInfo, so the paths
|
|
|
|
produced from different join combinations that produce equivalent joinrels
|
2000-02-15 21:49:31 +01:00
|
|
|
will compete in add_path.
|
2000-02-07 05:41:04 +01:00
|
|
|
|
|
|
|
Once we have built the final join rel, we use either the cheapest path
|
|
|
|
for it or the cheapest path with the desired ordering (if that's cheaper
|
|
|
|
than applying a sort to the cheapest other path).
|
|
|
|
|
1999-02-08 05:29:25 +01:00
|
|
|
|
1999-02-04 04:19:11 +01:00
|
|
|
Optimizer Functions
|
|
|
|
-------------------
|
|
|
|
|
2000-03-21 06:12:12 +01:00
|
|
|
The primary entry point is planner().
|
|
|
|
|
1997-12-17 19:02:33 +01:00
|
|
|
planner()
|
2000-03-21 06:12:12 +01:00
|
|
|
set up for recursive handling of subqueries
|
|
|
|
do final cleanup after planning.
|
|
|
|
-subquery_planner()
|
|
|
|
simplify constant expressions
|
|
|
|
canonicalize qual
|
2000-02-07 05:41:04 +01:00
|
|
|
Attempt to reduce WHERE clause to either CNF or DNF canonical form.
|
|
|
|
CNF (top-level-AND) is preferred, since the optimizer can then use
|
|
|
|
any of the AND subclauses to filter tuples; but quals that are in
|
|
|
|
or close to DNF form will suffer exponential expansion if we try to
|
|
|
|
force them to CNF. In pathological cases either transform may expand
|
|
|
|
the qual unreasonably; so we may have to leave it un-normalized,
|
|
|
|
thereby reducing the accuracy of selectivity estimates.
|
2000-03-21 06:12:12 +01:00
|
|
|
process sublinks
|
|
|
|
convert Vars of outer query levels into Params
|
|
|
|
--union_planner()
|
|
|
|
handle unions and inheritance by mutual recursion with prepunion.c routines
|
|
|
|
preprocess target list
|
|
|
|
handle GROUP BY, HAVING, aggregates, ORDER BY, DISTINCT
|
|
|
|
--query_planner()
|
1997-12-17 19:02:33 +01:00
|
|
|
pull out constants from target list
|
|
|
|
get a target list that only contains column names, no expressions
|
|
|
|
if none, then return
|
|
|
|
---subplanner()
|
|
|
|
make list of relations in target
|
|
|
|
make list of relations in where clause
|
1999-02-15 23:19:01 +01:00
|
|
|
split up the qual into restrictions (a=1) and joins (b=c)
|
|
|
|
find relation clauses can do merge sort and hash joins
|
|
|
|
----make_one_rel()
|
|
|
|
set_base_rel_pathlist()
|
|
|
|
find scan and all index paths for each relation
|
|
|
|
find selectivity of columns used in joins
|
|
|
|
-----make_one_rel_by_joins()
|
1997-12-17 19:02:33 +01:00
|
|
|
jump to geqo if needed
|
2000-02-07 05:41:04 +01:00
|
|
|
else call make_rels_by_joins() for each level of join tree needed
|
|
|
|
make_rels_by_joins():
|
|
|
|
For each joinrel of the prior level, do make_rels_by_clause_joins()
|
|
|
|
if it has join clauses, or make_rels_by_clauseless_joins() if not.
|
|
|
|
Also generate "bushy plan" joins between joinrels of lower levels.
|
|
|
|
Back at make_one_rel_by_joins(), apply set_cheapest() to extract the
|
|
|
|
cheapest path for each newly constructed joinrel.
|
|
|
|
Loop back if this wasn't the top join level.
|
1997-12-17 19:02:33 +01:00
|
|
|
do group(GROUP)
|
|
|
|
do aggregate
|
|
|
|
put back constants
|
|
|
|
re-flatten target list
|
|
|
|
make unique(DISTINCT)
|
|
|
|
make sort(ORDER BY)
|
1999-02-03 21:15:53 +01:00
|
|
|
|
|
|
|
|
1999-08-16 04:17:58 +02:00
|
|
|
Optimizer Data Structures
|
|
|
|
-------------------------
|
1999-02-04 04:19:11 +01:00
|
|
|
|
1999-02-15 23:19:01 +01:00
|
|
|
RelOptInfo - a relation or joined relations
|
1999-02-04 04:19:11 +01:00
|
|
|
|
1999-02-19 03:05:20 +01:00
|
|
|
RestrictInfo - restriction clauses, like "x = 3"
|
|
|
|
JoinInfo - join clauses, including the relids needed for the join
|
1999-02-04 04:19:11 +01:00
|
|
|
|
1999-02-15 23:19:01 +01:00
|
|
|
Path - every way to generate a RelOptInfo(sequential,index,joins)
|
2000-02-07 05:41:04 +01:00
|
|
|
SeqScan - a plain Path node with nodeTag = T_SeqScan
|
1999-02-15 23:19:01 +01:00
|
|
|
IndexPath - index scans
|
1999-08-16 04:17:58 +02:00
|
|
|
NestPath - nested-loop joins
|
1999-02-15 23:19:01 +01:00
|
|
|
MergePath - merge joins
|
|
|
|
HashPath - hash joins
|
1999-02-04 02:47:02 +01:00
|
|
|
|
2000-02-07 05:41:04 +01:00
|
|
|
PathKeys - a data structure representing the ordering of a path
|
1999-08-16 04:17:58 +02:00
|
|
|
|
|
|
|
The optimizer spends a good deal of its time worrying about the ordering
|
|
|
|
of the tuples returned by a path. The reason this is useful is that by
|
|
|
|
knowing the sort ordering of a path, we may be able to use that path as
|
|
|
|
the left or right input of a mergejoin and avoid an explicit sort step.
|
|
|
|
Nestloops and hash joins don't really care what the order of their inputs
|
|
|
|
is, but mergejoin needs suitably ordered inputs. Therefore, all paths
|
|
|
|
generated during the optimization process are marked with their sort order
|
|
|
|
(to the extent that it is known) for possible use by a higher-level merge.
|
|
|
|
|
|
|
|
It is also possible to avoid an explicit sort step to implement a user's
|
2000-02-07 05:41:04 +01:00
|
|
|
ORDER BY clause if the final path has the right ordering already, so the
|
|
|
|
sort ordering is of interest even at the top level. subplanner() will
|
|
|
|
look for the cheapest path with a sort order matching the desired order,
|
|
|
|
and will compare its cost to the cost of using the cheapest-overall path
|
|
|
|
and doing an explicit sort.
|
1999-08-16 04:17:58 +02:00
|
|
|
|
|
|
|
When we are generating paths for a particular RelOptInfo, we discard a path
|
|
|
|
if it is more expensive than another known path that has the same or better
|
|
|
|
sort order. We will never discard a path that is the only known way to
|
2000-02-07 05:41:04 +01:00
|
|
|
achieve a given sort order (without an explicit sort, that is). In this
|
|
|
|
way, the next level up will have the maximum freedom to build mergejoins
|
|
|
|
without sorting, since it can pick from any of the paths retained for its
|
|
|
|
inputs.
|
1999-08-16 04:17:58 +02:00
|
|
|
|
|
|
|
See path/pathkeys.c for an explanation of the PathKeys data structure that
|
|
|
|
represents what is known about the sort order of a particular Path.
|