⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 predmig.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * predmig.c * * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/_deadcode/predmig.c,v 1.4 1999/05/25 22:41:35 momjian Exp $ * *------------------------------------------------------------------------- *//*** DESCRIPTION** Main Routines to handle Predicate Migration (i.e. correct optimization** of queries with expensive functions.)****	  The reasoning behind some of these algorithms is rather detailed.** Have a look at Sequoia Tech Report 92/13 for more info.	Also** see Monma and Sidney's paper "Sequencing with Series-Parallel** Precedence Constraints", in "Mathematics of Operations Research",** volume 4 (1979),  pp. 215-224.****	  The main thing that this code does that wasn't handled in xfunc.c is** it considers the possibility that two joins in a stream may not** be ordered by ascending rank -- in such a scenario, it may be optimal** to pullup more restrictions than we did via xfunc_try_pullup.****	  This code in some sense generalizes xfunc_try_pullup; if you** run postgres -x noprune, you'll turn off xfunc_try_pullup, and this** code will do everything that xfunc_try_pullup would have, and maybe** more.  However, this results in no pruning, which may slow down the** optimizer and/or cause the system to run out of memory.**										   -- JMH, 11/13/92*/#include "nodes/pg_list.h"#include "nodes/nodes.h"#include "nodes/primnodes.h"#include "nodes/relation.h"#include "utils/palloc.h"#include "utils/elog.h"#include "optimizer/xfunc.h"#include "optimizer/pathnode.h"#include "optimizer/internal.h"#include "optimizer/cost.h"#include "optimizer/keys.h"#include "optimizer/tlist.h"#define is_clause(node) (get_cinfo(node))		/* a stream node												 * represents a clause												 * (not a join) iff it has												 * a non-NULL cinfo field */static void xfunc_predmig(JoinPath pathnode, Stream streamroot,			  Stream laststream, bool *progressp);static bool xfunc_series_llel(Stream stream);static bool xfunc_llel_chains(Stream root, Stream bottom);static Stream xfunc_complete_stream(Stream stream);static bool xfunc_prdmig_pullup(Stream origstream, Stream pullme,					JoinPath joinpath);static void xfunc_form_groups(Stream root, Stream bottom);static void xfunc_free_stream(Stream root);static Stream xfunc_add_clauses(Stream current);static void xfunc_setup_group(Stream node, Stream bottom);static Stream xfunc_streaminsert(RestrictInfo restrictinfo, Stream current,				   int clausetype);static int	xfunc_num_relids(Stream node);static StreamPtr xfunc_get_downjoin(Stream node);static StreamPtr xfunc_get_upjoin(Stream node);static Stream xfunc_stream_qsort(Stream root, Stream bottom);static int	xfunc_stream_compare(void *arg1, void *arg2);static bool xfunc_check_stream(Stream node);static bool xfunc_in_stream(Stream node, Stream stream);/* -----------------   MAIN FUNCTIONS ------------------------ *//*** xfunc_do_predmig**	  wrapper for Predicate Migration.	It calls xfunc_predmig until no** more progress is made.**	  return value says if any changes were ever made.*/boolxfunc_do_predmig(Path root){	bool		progress,				changed = false;	if (is_join(root))		do		{			progress = false;			Assert(IsA(root, JoinPath));			xfunc_predmig((JoinPath) root, (Stream) NULL, (Stream) NULL,						  &progress);			if (changed && progress)				elog(DEBUG, "Needed to do a second round of predmig!\n");			if (progress)				changed = true;		} while (progress);	return changed;}/* ** xfunc_predmig **  The main routine for Predicate Migration.	It traverses a join tree, ** and for each root-to-leaf path in the plan tree it constructs a ** "Stream", which it passes to xfunc_series_llel for optimization. ** Destructively modifies the join tree (via predicate pullup). */static voidxfunc_predmig(JoinPath pathnode,/* root of the join tree */			  Stream streamroot,			  Stream laststream,/* for recursive calls -- these are the								 * root of the stream under construction,								 * and the lowest node created so far */			  bool *progressp){	Stream		newstream;	/*	 * * traverse the join tree dfs-style, constructing a stream as you	 * go. * When you hit a scan node, pass the stream off to	 * xfunc_series_llel.	 */	/* sanity check */	if ((!streamroot && laststream) ||		(streamroot && !laststream))		elog(ERROR, "called xfunc_predmig with bad inputs");	if (streamroot)		Assert(xfunc_check_stream(streamroot));	/* add path node to stream */	newstream = RMakeStream();	if (!streamroot)		streamroot = newstream;	set_upstream(newstream, (StreamPtr) laststream);	if (laststream)		set_downstream(laststream, (StreamPtr) newstream);	set_downstream(newstream, (StreamPtr) NULL);	set_pathptr(newstream, (pathPtr) pathnode);	set_cinfo(newstream, (RestrictInfo) NULL);	set_clausetype(newstream, XFUNC_UNKNOWN);	/* base case: we're at a leaf, call xfunc_series_llel */	if (!is_join(pathnode))	{		/* form a fleshed-out copy of the stream */		Stream		fullstream = xfunc_complete_stream(streamroot);		/* sort it via series-llel */		if (xfunc_series_llel(fullstream))			*progressp = true;		/* free up the copy */		xfunc_free_stream(fullstream);	}	else	{		/* visit left child */		xfunc_predmig((JoinPath) get_outerjoinpath(pathnode),					  streamroot, newstream, progressp);		/* visit right child */		xfunc_predmig((JoinPath) get_innerjoinpath(pathnode),					  streamroot, newstream, progressp);	}	/* remove this node */	if (get_upstream(newstream))		set_downstream((Stream) get_upstream(newstream), (StreamPtr) NULL);	pfree(newstream);}/* ** xfunc_series_llel **    A flavor of Monma and Sidney's Series-Parallel algorithm. ** Traverse stream downwards.	When you find a node with restrictions on it, ** call xfunc_llel_chains on the substream from root to that node. */static boolxfunc_series_llel(Stream stream){	Stream		temp,				next;	bool		progress = false;	for (temp = stream; temp != (Stream) NULL; temp = next)	{		next = (Stream) xfunc_get_downjoin(temp);		/*		 * * if there are restrictions/secondary join clauses above this *		 * node, call xfunc_llel_chains		 */		if (get_upstream(temp) && is_clause((Stream) get_upstream(temp)))			if (xfunc_llel_chains(stream, temp))				progress = true;	}	return progress;}/* ** xfunc_llel_chains **    A flavor of Monma and Sidney's Parallel Chains algorithm. ** Given a stream which has been well-ordered except for its lowermost ** restrictions/2-ary joins, pull up the restrictions/2-arys as appropriate. ** What that means here is to form groups in the chain above the lowest ** join node above bottom inclusive, and then take all the restrictions ** following bottom, and try to pull them up as far as possible. */static boolxfunc_llel_chains(Stream root, Stream bottom){	bool		progress = false;	Stream		origstream;	Stream		tmpstream,				pathstream;	Stream		rootcopy = root;	Assert(xfunc_check_stream(root));	/* xfunc_prdmig_pullup will need an unmodified copy of the stream */	origstream = (Stream) copyObject((Node) root);	/* form groups among ill-ordered nodes */	xfunc_form_groups(root, bottom);	/* sort chain by rank */	Assert(xfunc_in_stream(bottom, root));	rootcopy = xfunc_stream_qsort(root, bottom);	/*	 * * traverse sorted stream -- if any restriction has moved above a	 * join, * we must pull it up in the plan.	That is, make plan tree *	 * reflect order of sorted stream.	 */	for (tmpstream = rootcopy,		 pathstream = (Stream) xfunc_get_downjoin(rootcopy);		 tmpstream != (Stream) NULL && pathstream != (Stream) NULL;		 tmpstream = (Stream) get_downstream(tmpstream))	{		if (is_clause(tmpstream)			&& get_pathptr(pathstream) != get_pathptr(tmpstream))		{			/*			 * * If restriction moved above a Join after sort, we pull it *			 * up in the join plan. *	 If restriction moved down, we			 * ignore it. * This is because Joey's Sequoia paper proves			 * that * restrictions should never move down.	If this * one			 * were moved down, it would violate "semantic correctness", *			 * i.e. it would be lower than the attributes it references.			 */			Assert(xfunc_num_relids(pathstream) > xfunc_num_relids(tmpstream));			progress = xfunc_prdmig_pullup(origstream, tmpstream,									 (JoinPath) get_pathptr(pathstream));		}		if (get_downstream(tmpstream))			pathstream = (Stream) xfunc_get_downjoin((Stream) get_downstream(tmpstream));	}	/* free up origstream */	xfunc_free_stream(origstream);	return progress;}/* ** xfunc_complete_stream **   Given a stream composed of join nodes only, make a copy containing the ** join nodes along with the associated restriction nodes. */static Streamxfunc_complete_stream(Stream stream){	Stream		tmpstream,				copystream,				curstream = (Stream) NULL;	copystream = (Stream) copyObject((Node) stream);	Assert(xfunc_check_stream(copystream));	curstream = copystream;	Assert(!is_clause(curstream));	/* curstream = (Stream)xfunc_get_downjoin(curstream); */	while (curstream != (Stream) NULL)	{		xfunc_add_clauses(curstream);		curstream = (Stream) xfunc_get_downjoin(curstream);	}	/* find top of stream and return it */	for (tmpstream = copystream; get_upstream(tmpstream) != (StreamPtr) NULL;		 tmpstream = (Stream) get_upstream(tmpstream))		 /* no body in for loop */ ;	return tmpstream;}/* ** xfunc_prdmig_pullup **    pullup a clause in a path above joinpath.  Since the JoinPath tree ** doesn't have upward pointers, it's difficult to deal with.	Thus we ** require the original stream, which maintains pointers to all the path ** nodes.	We use the original stream to find out what joins are ** above the clause. */static boolxfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath){	RestrictInfo restrictinfo = get_cinfo(pullme);	bool		progress = false;	Stream		upjoin,				orignode,				temp;	int			whichchild;	/* find node in origstream that contains clause */	for (orignode = origstream;		 orignode != (Stream) NULL		 && get_cinfo(orignode) != restrictinfo;		 orignode = (Stream) get_downstream(orignode))		 /* empty body in for loop */ ;	if (!orignode)		elog(ERROR, "Didn't find matching node in original stream");	/* pull up this node as far as it should go */	for (upjoin = (Stream) xfunc_get_upjoin(orignode);		 upjoin != (Stream) NULL		 && (JoinPath) get_pathptr((Stream) xfunc_get_downjoin(upjoin))		 != joinpath;		 upjoin = (Stream) xfunc_get_upjoin(upjoin))	{#ifdef DEBUG		elog(DEBUG, "pulling up in xfunc_predmig_pullup!");#endif		/* move clause up in path */		if (get_pathptr((Stream) get_downstream(upjoin))		  == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)))			whichchild = OUTER;		else			whichchild = INNER;		restrictinfo = xfunc_pullup((Path) get_pathptr((Stream) get_downstream(upjoin)),									(JoinPath) get_pathptr(upjoin),									restrictinfo,									whichchild,									get_clausetype(orignode));		set_pathptr(pullme, get_pathptr(upjoin));		/* pullme has been moved into locrestrictinfo */		set_clausetype(pullme, XFUNC_LOCPRD);		/*		 * * xfunc_pullup makes new path nodes for children of *		 * get_pathptr(current). We must modify the stream nodes to point *		 * to these path nodes		 */		if (whichchild == OUTER)		{			for (temp = (Stream) get_downstream(upjoin); is_clause(temp);				 temp = (Stream) get_downstream(temp))				set_pathptr					(temp, (pathPtr)					 get_outerjoinpath((JoinPath) get_pathptr(upjoin)));			set_pathptr				(temp,			(pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)));		}		else		{			for (temp = (Stream) get_downstream(upjoin); is_clause(temp);				 temp = (Stream) get_downstream(temp))				set_pathptr					(temp, (pathPtr)					 get_innerjoinpath((JoinPath) get_pathptr(upjoin)));			set_pathptr				(temp, (pathPtr)				 get_innerjoinpath((JoinPath) get_pathptr(upjoin)));		}		progress = true;	}	if (!progress)		elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup");	return progress;}/* ** xfunc_form_groups **    A group is a pair of stream nodes a,b such that a is constrained to ** precede b (for instance if a and b are both joins), but rank(a) > rank(b). ** In such a situation, Monma and Sidney prove that no clauses should end ** up between a and b, and therefore we may treat them as a group, with ** selectivity equal to the product of their selectivities, and cost ** equal to the cost of the first plus the selectivity of the first times the ** cost of the second.  We define each node to be in a group by itself, ** and then repeatedly find adjacent groups which are ordered by descending ** rank, and make larger groups.  You know that two adjacent nodes are in a ** group together if the lower has groupup set to true.  They will both have ** the same groupcost and groupsel (since they're in the same group!) */static voidxfunc_form_groups(Query *queryInfo, Stream root, Stream bottom)

⌨️ 快捷键说明

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