indxpath.c

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

C
2,070
字号
/*------------------------------------------------------------------------- * * indxpath.c *	  Routines to determine which indexes are usable for scanning a *	  given relation, and create Paths accordingly. * * 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/indxpath.c,v 1.227.2.1 2008/09/12 14:56:19 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <math.h>#include "access/skey.h"#include "catalog/pg_am.h"#include "catalog/pg_operator.h"#include "catalog/pg_opfamily.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "optimizer/predtest.h"#include "optimizer/restrictinfo.h"#include "optimizer/var.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/pg_locale.h"#include "utils/selfuncs.h"/* * DoneMatchingIndexKeys() - MACRO */#define DoneMatchingIndexKeys(families) (families[0] == InvalidOid)#define IsBooleanOpfamily(opfamily) \	((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID)/* Per-path data used within choose_bitmap_and() */typedef struct{	Path	   *path;			/* IndexPath, BitmapAndPath, or BitmapOrPath */	List	   *quals;			/* the WHERE clauses it uses */	List	   *preds;			/* predicates of its partial index(es) */	Bitmapset  *clauseids;		/* quals+preds represented as a bitmapset */} PathClauseUsage;static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,					List *clauses, List *outer_clauses,					bool istoplevel, RelOptInfo *outer_rel,					SaOpControl saop_control);static List *find_saop_paths(PlannerInfo *root, RelOptInfo *rel,				List *clauses, List *outer_clauses,				bool istoplevel, RelOptInfo *outer_rel);static Path *choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,				  List *paths, RelOptInfo *outer_rel);static int	path_usage_comparator(const void *a, const void *b);static Cost bitmap_scan_cost_est(PlannerInfo *root, RelOptInfo *rel,					 Path *ipath, RelOptInfo *outer_rel);static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel,					List *paths, RelOptInfo *outer_rel);static PathClauseUsage *classify_index_clause_usage(Path *path,							List **clauselist);static void find_indexpath_quals(Path *bitmapqual, List **quals, List **preds);static int	find_list_position(Node *node, List **nodelist);static bool match_clause_to_indexcol(IndexOptInfo *index,						 int indexcol, Oid opfamily,						 RestrictInfo *rinfo,						 Relids outer_relids,						 SaOpControl saop_control);static bool is_indexable_operator(Oid expr_op, Oid opfamily,					  bool indexkey_on_left);static bool match_rowcompare_to_indexcol(IndexOptInfo *index,							 int indexcol,							 Oid opfamily,							 RowCompareExpr *clause,							 Relids outer_relids);static Relids indexable_outerrelids(PlannerInfo *root, RelOptInfo *rel);static bool matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel,				  Relids outer_relids);static List *find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,					  Relids outer_relids, bool isouterjoin);static bool match_boolean_index_clause(Node *clause, int indexcol,						   IndexOptInfo *index);static bool match_special_index_operator(Expr *clause, Oid opfamily,							 bool indexkey_on_left);static Expr *expand_boolean_index_clause(Node *clause, int indexcol,							IndexOptInfo *index);static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily);static RestrictInfo *expand_indexqual_rowcompare(RestrictInfo *rinfo,							IndexOptInfo *index,							int indexcol);static List *prefix_quals(Node *leftop, Oid opfamily,			 Const *prefix, Pattern_Prefix_Status pstatus);static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily,					 Datum rightop);static Datum string_to_datum(const char *str, Oid datatype);static Const *string_to_const(const char *str, Oid datatype);/* * create_index_paths() *	  Generate all interesting index paths for the given relation. *	  Candidate paths are added to the rel's pathlist (using add_path). * * To be considered for an index scan, an index must match one or more * restriction clauses or join clauses from the query's qual condition, * or match the query's ORDER BY condition, or have a predicate that * matches the query's qual condition. * * There are two basic kinds of index scans.  A "plain" index scan uses * only restriction clauses (possibly none at all) in its indexqual, * so it can be applied in any context.  An "innerjoin" index scan uses * join clauses (plus restriction clauses, if available) in its indexqual. * Therefore it can only be used as the inner relation of a nestloop * join against an outer rel that includes all the other rels mentioned * in its join clauses.  In that context, values for the other rels' * attributes are available and fixed during any one scan of the indexpath. * * An IndexPath is generated and submitted to add_path() for each plain index * scan this routine deems potentially interesting for the current query. * * We also determine the set of other relids that participate in join * clauses that could be used with each index.	The actually best innerjoin * path will be generated for each outer relation later on, but knowing the * set of potential otherrels allows us to identify equivalent outer relations * and avoid repeated computation. * * 'rel' is the relation for which we want to generate index paths * * Note: check_partial_indexes() must have been run previously for this rel. */voidcreate_index_paths(PlannerInfo *root, RelOptInfo *rel){	List	   *indexpaths;	List	   *bitindexpaths;	ListCell   *l;	/* Skip the whole mess if no indexes */	if (rel->indexlist == NIL)	{		rel->index_outer_relids = NULL;		return;	}	/*	 * Examine join clauses to see which ones are potentially usable with	 * indexes of this rel, and generate the set of all other relids that	 * participate in such join clauses.  We'll use this set later to	 * recognize outer rels that are equivalent for joining purposes.	 */	rel->index_outer_relids = indexable_outerrelids(root, rel);	/*	 * Find all the index paths that are directly usable for this relation	 * (ie, are valid without considering OR or JOIN clauses).	 */	indexpaths = find_usable_indexes(root, rel,									 rel->baserestrictinfo, NIL,									 true, NULL, SAOP_FORBID);	/*	 * We can submit them all to add_path.	(This generates access paths for	 * plain IndexScan plans.)	However, for the next step we will only want	 * the ones that have some selectivity; we must discard anything that was	 * generated solely for ordering purposes.	 */	bitindexpaths = NIL;	foreach(l, indexpaths)	{		IndexPath  *ipath = (IndexPath *) lfirst(l);		add_path(rel, (Path *) ipath);		if (ipath->indexselectivity < 1.0 &&			!ScanDirectionIsBackward(ipath->indexscandir))			bitindexpaths = lappend(bitindexpaths, ipath);	}	/*	 * Generate BitmapOrPaths for any suitable OR-clauses present in the	 * restriction list.  Add these to bitindexpaths.	 */	indexpaths = generate_bitmap_or_paths(root, rel,										  rel->baserestrictinfo, NIL,										  NULL);	bitindexpaths = list_concat(bitindexpaths, indexpaths);	/*	 * Likewise, generate paths using ScalarArrayOpExpr clauses; these can't	 * be simple indexscans but they can be used in bitmap scans.	 */	indexpaths = find_saop_paths(root, rel,								 rel->baserestrictinfo, NIL,								 true, NULL);	bitindexpaths = list_concat(bitindexpaths, indexpaths);	/*	 * If we found anything usable, generate a BitmapHeapPath for the most	 * promising combination of bitmap index paths.	 */	if (bitindexpaths != NIL)	{		Path	   *bitmapqual;		BitmapHeapPath *bpath;		bitmapqual = choose_bitmap_and(root, rel, bitindexpaths, NULL);		bpath = create_bitmap_heap_path(root, rel, bitmapqual, NULL);		add_path(rel, (Path *) bpath);	}}/*---------- * find_usable_indexes *	  Given a list of restriction clauses, find all the potentially usable *	  indexes for the given relation, and return a list of IndexPaths. * * The caller actually supplies two lists of restriction clauses: some * "current" ones and some "outer" ones.  Both lists can be used freely * to match keys of the index, but an index must use at least one of the * "current" clauses to be considered usable.  The motivation for this is * examples like *		WHERE (x = 42) AND (... OR (y = 52 AND z = 77) OR ....) * While we are considering the y/z subclause of the OR, we can use "x = 42" * as one of the available index conditions; but we shouldn't match the * subclause to any index on x alone, because such a Path would already have * been generated at the upper level.  So we could use an index on x,y,z * or an index on x,y for the OR subclause, but not an index on just x. * When dealing with a partial index, a match of the index predicate to * one of the "current" clauses also makes the index usable. * * If istoplevel is true (indicating we are considering the top level of a * rel's restriction clauses), we will include indexes in the result that * have an interesting sort order, even if they have no matching restriction * clauses. * * 'rel' is the relation for which we want to generate index paths * 'clauses' is the current list of clauses (RestrictInfo nodes) * 'outer_clauses' is the list of additional upper-level clauses * 'istoplevel' is true if clauses are the rel's top-level restriction list *		(outer_clauses must be NIL when this is true) * 'outer_rel' is the outer side of the join if forming an inner indexscan *		(so some of the given clauses are join clauses); NULL if not * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used * * Note: check_partial_indexes() must have been run previously. *---------- */static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,					List *clauses, List *outer_clauses,					bool istoplevel, RelOptInfo *outer_rel,					SaOpControl saop_control){	Relids		outer_relids = outer_rel ? outer_rel->relids : NULL;	bool		possibly_useful_pathkeys = has_useful_pathkeys(root, rel);	List	   *result = NIL;	List	   *all_clauses = NIL;		/* not computed till needed */	ListCell   *ilist;	foreach(ilist, rel->indexlist)	{		IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);		IndexPath  *ipath;		List	   *restrictclauses;		List	   *index_pathkeys;		List	   *useful_pathkeys;		bool		useful_predicate;		bool		found_clause;		bool		index_is_ordered;		/*		 * Ignore partial indexes that do not match the query.	If a partial		 * index is marked predOK then we know it's OK; otherwise, if we are		 * at top level we know it's not OK (since predOK is exactly whether		 * its predicate could be proven from the toplevel clauses).		 * Otherwise, we have to test whether the added clauses are sufficient		 * to imply the predicate.	If so, we could use the index in the		 * current context.		 *		 * We set useful_predicate to true iff the predicate was proven using		 * the current set of clauses.	This is needed to prevent matching a		 * predOK index to an arm of an OR, which would be a legal but		 * pointlessly inefficient plan.  (A better plan will be generated by		 * just scanning the predOK index alone, no OR.)		 */		useful_predicate = false;		if (index->indpred != NIL)		{			if (index->predOK)			{				if (istoplevel)				{					/* we know predicate was proven from these clauses */					useful_predicate = true;				}			}			else			{				if (istoplevel)					continue;	/* no point in trying to prove it */				/* Form all_clauses if not done already */				if (all_clauses == NIL)					all_clauses = list_concat(list_copy(clauses),											  outer_clauses);				if (!predicate_implied_by(index->indpred, all_clauses))					continue;	/* can't use it at all */				if (!predicate_implied_by(index->indpred, outer_clauses))					useful_predicate = true;			}		}		/*		 * 1. Match the index against the available restriction clauses.		 * found_clause is set true only if at least one of the current		 * clauses was used (and, if saop_control is SAOP_REQUIRE, it has to		 * have been a ScalarArrayOpExpr clause).		 */		restrictclauses = group_clauses_by_indexkey(index,													clauses,													outer_clauses,													outer_relids,													saop_control,													&found_clause);		/*		 * Not all index AMs support scans with no restriction clauses. We		 * can't generate a scan over an index with amoptionalkey = false		 * unless there's at least one restriction clause.		 */		if (restrictclauses == NIL && !index->amoptionalkey)			continue;		/*		 * 2. Compute pathkeys describing index's ordering, if any, then see		 * how many of them are actually useful for this query.  This is not		 * relevant unless we are at top level.		 */		index_is_ordered = OidIsValid(index->fwdsortop[0]);		if (index_is_ordered && possibly_useful_pathkeys &&			istoplevel && outer_rel == NULL)		{			index_pathkeys = build_index_pathkeys(root, index,												  ForwardScanDirection);			useful_pathkeys = truncate_useless_pathkeys(root, rel,														index_pathkeys);		}		else			useful_pathkeys = NIL;		/*		 * 3. Generate an indexscan path if there are relevant restriction		 * clauses in the current clauses, OR the index ordering is		 * potentially useful for later merging or final output ordering, OR		 * the index has a predicate that was proven by the current clauses.		 */		if (found_clause || useful_pathkeys != NIL || useful_predicate)		{			ipath = create_index_path(root, index,									  restrictclauses,									  useful_pathkeys,									  index_is_ordered ?									  ForwardScanDirection :									  NoMovementScanDirection,									  outer_rel);			result = lappend(result, ipath);		}		/*		 * 4. If the index is ordered, a backwards scan might be interesting.		 * Again, this is only interesting at top level.		 */		if (index_is_ordered && possibly_useful_pathkeys &&			istoplevel && outer_rel == NULL)		{			index_pathkeys = build_index_pathkeys(root, index,												  BackwardScanDirection);			useful_pathkeys = truncate_useless_pathkeys(root, rel,														index_pathkeys);			if (useful_pathkeys != NIL)			{				ipath = create_index_path(root, index,										  restrictclauses,										  useful_pathkeys,										  BackwardScanDirection,										  outer_rel);				result = lappend(result, ipath);			}		}	}	return result;}/* * find_saop_paths *		Find all the potential indexpaths that make use of ScalarArrayOpExpr *		clauses.  The executor only supports these in bitmap scans, not

⌨️ 快捷键说明

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