joinpath.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 999 行 · 第 1/3 页

C
999
字号
/*------------------------------------------------------------------------- * * joinpath.c *	  Routines to find all possible paths for processing a set of joins * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.115.2.1 2008/03/24 21:53:12 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <math.h>#include "optimizer/cost.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,					 RelOptInfo *outerrel, RelOptInfo *innerrel,					 List *restrictlist, List *mergeclause_list,					 JoinType jointype);static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel,					 RelOptInfo *outerrel, RelOptInfo *innerrel,					 List *restrictlist, List *mergeclause_list,					 JoinType jointype);static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,					 RelOptInfo *outerrel, RelOptInfo *innerrel,					 List *restrictlist, JoinType jointype);static Path *best_appendrel_indexscan(PlannerInfo *root, RelOptInfo *rel,						 RelOptInfo *outer_rel, JoinType jointype);static List *select_mergejoin_clauses(PlannerInfo *root,						 RelOptInfo *joinrel,						 RelOptInfo *outerrel,						 RelOptInfo *innerrel,						 List *restrictlist,						 JoinType jointype);/* * add_paths_to_joinrel *	  Given a join relation and two component rels from which it can be made, *	  consider all possible paths that use the two component rels as outer *	  and inner rel respectively.  Add these paths to the join rel's pathlist *	  if they survive comparison with other paths (and remove any existing *	  paths that are dominated by these paths). * * Modifies the pathlist field of the joinrel node to contain the best * paths found so far. */voidadd_paths_to_joinrel(PlannerInfo *root,					 RelOptInfo *joinrel,					 RelOptInfo *outerrel,					 RelOptInfo *innerrel,					 JoinType jointype,					 List *restrictlist){	List	   *mergeclause_list = NIL;	/*	 * Find potential mergejoin clauses.  We can skip this if we are not	 * interested in doing a mergejoin.  However, mergejoin is currently our	 * only way of implementing full outer joins, so override mergejoin	 * disable if it's a full join.	 */	if (enable_mergejoin || jointype == JOIN_FULL)		mergeclause_list = select_mergejoin_clauses(root,													joinrel,													outerrel,													innerrel,													restrictlist,													jointype);	/*	 * 1. Consider mergejoin paths where both relations must be explicitly	 * sorted.	 */	sort_inner_and_outer(root, joinrel, outerrel, innerrel,						 restrictlist, mergeclause_list, jointype);	/*	 * 2. Consider paths where the outer relation need not be explicitly	 * sorted. This includes both nestloops and mergejoins where the outer	 * path is already ordered.	 */	match_unsorted_outer(root, joinrel, outerrel, innerrel,						 restrictlist, mergeclause_list, jointype);#ifdef NOT_USED	/*	 * 3. Consider paths where the inner relation need not be explicitly	 * sorted.	This includes mergejoins only (nestloops were already built in	 * match_unsorted_outer).	 *	 * Diked out as redundant 2/13/2000 -- tgl.  There isn't any really	 * significant difference between the inner and outer side of a mergejoin,	 * so match_unsorted_inner creates no paths that aren't equivalent to	 * those made by match_unsorted_outer when add_paths_to_joinrel() is	 * invoked with the two rels given in the other order.	 */	match_unsorted_inner(root, joinrel, outerrel, innerrel,						 restrictlist, mergeclause_list, jointype);#endif	/*	 * 4. Consider paths where both outer and inner relations must be hashed	 * before being joined.	 */	if (enable_hashjoin)		hash_inner_and_outer(root, joinrel, outerrel, innerrel,							 restrictlist, jointype);}/* * sort_inner_and_outer *	  Create mergejoin join paths by explicitly sorting both the outer and *	  inner join relations on each available merge ordering. * * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation * 'restrictlist' contains all of the RestrictInfo nodes for restriction *		clauses that apply to this join * 'mergeclause_list' is a list of RestrictInfo nodes for available *		mergejoin clauses in this join * 'jointype' is the type of join to do */static voidsort_inner_and_outer(PlannerInfo *root,					 RelOptInfo *joinrel,					 RelOptInfo *outerrel,					 RelOptInfo *innerrel,					 List *restrictlist,					 List *mergeclause_list,					 JoinType jointype){	bool		useallclauses;	Path	   *outer_path;	Path	   *inner_path;	List	   *all_pathkeys;	ListCell   *l;	/*	 * If we are doing a right or full join, we must use *all* the	 * mergeclauses as join clauses, else we will not have a valid plan.	 */	switch (jointype)	{		case JOIN_INNER:		case JOIN_LEFT:		case JOIN_IN:		case JOIN_UNIQUE_OUTER:		case JOIN_UNIQUE_INNER:			useallclauses = false;			break;		case JOIN_RIGHT:		case JOIN_FULL:			useallclauses = true;			break;		default:			elog(ERROR, "unrecognized join type: %d",				 (int) jointype);			useallclauses = false;		/* keep compiler quiet */			break;	}	/*	 * We only consider the cheapest-total-cost input paths, since we are	 * assuming here that a sort is required.  We will consider	 * cheapest-startup-cost input paths later, and only if they don't need a	 * sort.	 *	 * If unique-ification is requested, do it and then handle as a plain	 * inner join.	 */	outer_path = outerrel->cheapest_total_path;	inner_path = innerrel->cheapest_total_path;	if (jointype == JOIN_UNIQUE_OUTER)	{		outer_path = (Path *) create_unique_path(root, outerrel, outer_path);		jointype = JOIN_INNER;	}	else if (jointype == JOIN_UNIQUE_INNER)	{		inner_path = (Path *) create_unique_path(root, innerrel, inner_path);		jointype = JOIN_INNER;	}	/*	 * Each possible ordering of the available mergejoin clauses will generate	 * a differently-sorted result path at essentially the same cost.  We have	 * no basis for choosing one over another at this level of joining, but	 * some sort orders may be more useful than others for higher-level	 * mergejoins, so it's worth considering multiple orderings.	 *	 * Actually, it's not quite true that every mergeclause ordering will	 * generate a different path order, because some of the clauses may be	 * partially redundant (refer to the same EquivalenceClasses).	Therefore,	 * what we do is convert the mergeclause list to a list of canonical	 * pathkeys, and then consider different orderings of the pathkeys.	 *	 * Generating a path for *every* permutation of the pathkeys doesn't seem	 * like a winning strategy; the cost in planning time is too high. For	 * now, we generate one path for each pathkey, listing that pathkey first	 * and the rest in random order.  This should allow at least a one-clause	 * mergejoin without re-sorting against any other possible mergejoin	 * partner path.  But if we've not guessed the right ordering of secondary	 * keys, we may end up evaluating clauses as qpquals when they could have	 * been done as mergeclauses.  (In practice, it's rare that there's more	 * than two or three mergeclauses, so expending a huge amount of thought	 * on that is probably not worth it.)	 *	 * The pathkey order returned by select_outer_pathkeys_for_merge() has	 * some heuristics behind it (see that function), so be sure to try it	 * exactly as-is as well as making variants.	 */	all_pathkeys = select_outer_pathkeys_for_merge(root,												   mergeclause_list,												   joinrel);	foreach(l, all_pathkeys)	{		List	   *front_pathkey = (List *) lfirst(l);		List	   *cur_mergeclauses;		List	   *outerkeys;		List	   *innerkeys;		List	   *merge_pathkeys;		/* Make a pathkey list with this guy first */		if (l != list_head(all_pathkeys))			outerkeys = lcons(front_pathkey,							  list_delete_ptr(list_copy(all_pathkeys),											  front_pathkey));		else			outerkeys = all_pathkeys;	/* no work at first one... */		/* Sort the mergeclauses into the corresponding ordering */		cur_mergeclauses = find_mergeclauses_for_pathkeys(root,														  outerkeys,														  true,														  mergeclause_list);		/* Should have used them all... */		Assert(list_length(cur_mergeclauses) == list_length(mergeclause_list));		/* Build sort pathkeys for the inner side */		innerkeys = make_inner_pathkeys_for_merge(root,												  cur_mergeclauses,												  outerkeys);		/* Build pathkeys representing output sort order */		merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,											 outerkeys);		/*		 * And now we can make the path.		 *		 * Note: it's possible that the cheapest paths will already be sorted		 * properly.  create_mergejoin_path will detect that case and suppress		 * an explicit sort step, so we needn't do so here.		 */		add_path(joinrel, (Path *)				 create_mergejoin_path(root,									   joinrel,									   jointype,									   outer_path,									   inner_path,									   restrictlist,									   merge_pathkeys,									   cur_mergeclauses,									   outerkeys,									   innerkeys));	}}/* * match_unsorted_outer *	  Creates possible join paths for processing a single join relation *	  'joinrel' by employing either iterative substitution or *	  mergejoining on each of its possible outer paths (considering *	  only outer paths that are already ordered well enough for merging). * * We always generate a nestloop path for each available outer path. * In fact we may generate as many as five: one on the cheapest-total-cost * inner path, one on the same with materialization, one on the * cheapest-startup-cost inner path (if different), one on the * cheapest-total inner-indexscan path (if any), and one on the * cheapest-startup inner-indexscan path (if different). * * We also consider mergejoins if mergejoin clauses are available.	We have * two ways to generate the inner path for a mergejoin: sort the cheapest * inner path, or use an inner path that is already suitably ordered for the * merge.  If we have several mergeclauses, it could be that there is no inner * path (or only a very expensive one) for the full list of mergeclauses, but * better paths exist if we truncate the mergeclause list (thereby discarding * some sort key requirements).  So, we consider truncations of the * mergeclause list as well as the full list.  (Ideally we'd consider all * subsets of the mergeclause list, but that seems way too expensive.) * * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation * 'restrictlist' contains all of the RestrictInfo nodes for restriction *		clauses that apply to this join * 'mergeclause_list' is a list of RestrictInfo nodes for available *		mergejoin clauses in this join * 'jointype' is the type of join to do */static voidmatch_unsorted_outer(PlannerInfo *root,					 RelOptInfo *joinrel,					 RelOptInfo *outerrel,					 RelOptInfo *innerrel,					 List *restrictlist,					 List *mergeclause_list,					 JoinType jointype){	JoinType	save_jointype = jointype;	bool		nestjoinOK;	bool		useallclauses;	Path	   *inner_cheapest_startup = innerrel->cheapest_startup_path;	Path	   *inner_cheapest_total = innerrel->cheapest_total_path;	Path	   *matpath = NULL;	Path	   *index_cheapest_startup = NULL;	Path	   *index_cheapest_total = NULL;	ListCell   *l;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?