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

📄 indxpath.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * indxpath.c *	  Routines to determine which indexes are usable for scanning a *	  given relation, and create Paths accordingly. * * Portions Copyright (c) 1996-2005, 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.191.2.8 2006/05/18 19:56:56 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <math.h>#include "access/skey.h"#include "catalog/pg_opclass.h"#include "catalog/pg_operator.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 "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/pg_locale.h"#include "utils/selfuncs.h"/* * DoneMatchingIndexKeys() - MACRO */#define DoneMatchingIndexKeys(classes)	(classes[0] == InvalidOid)#define is_indexable_operator(clause,opclass,indexkey_on_left) \	(indexable_operator(clause,opclass,indexkey_on_left) != InvalidOid)#define IsBooleanOpclass(opclass) \	((opclass) == BOOL_BTREE_OPS_OID || (opclass) == BOOL_HASH_OPS_OID)static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,					List *clauses, List *outer_clauses,					bool istoplevel, bool isjoininner,					Relids outer_relids);static Path *choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths);static int	bitmap_path_comparator(const void *a, const void *b);static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths);static List *pull_indexpath_quals(Path *bitmapqual);static bool lists_intersect_ptr(List *list1, List *list2);static bool match_clause_to_indexcol(IndexOptInfo *index,						 int indexcol, Oid opclass,						 RestrictInfo *rinfo,						 Relids outer_relids);static Oid indexable_operator(Expr *clause, Oid opclass,				   bool indexkey_on_left);static Relids indexable_outerrelids(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 ScanDirection match_variant_ordering(PlannerInfo *root,					   IndexOptInfo *index,					   List *restrictclauses);static List *identify_ignorable_ordering_cols(PlannerInfo *root,								 IndexOptInfo *index,								 List *restrictclauses);static bool match_index_to_query_keys(PlannerInfo *root,						  IndexOptInfo *index,						  ScanDirection indexscandir,						  List *ignorables);static bool match_boolean_index_clause(Node *clause, int indexcol,						   IndexOptInfo *index);static bool match_special_index_operator(Expr *clause, Oid opclass,							 bool indexkey_on_left);static Expr *expand_boolean_index_clause(Node *clause, int indexcol,							IndexOptInfo *index);static List *expand_indexqual_condition(RestrictInfo *rinfo, Oid opclass);static List *prefix_quals(Node *leftop, Oid opclass,			 Const *prefix, Pattern_Prefix_Status pstatus);static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass,					 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. */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(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, false, NULL);	/*	 * 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,										  false, 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);		bpath = create_bitmap_heap_path(root, rel, bitmapqual, false);		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) * 'isjoininner' is true if forming an inner indexscan (so some of the *		given clauses are join clauses) * 'outer_relids' identifies the outer side of the join (pass NULL *		if not isjoininner) * * 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, bool isjoininner,					Relids outer_relids){	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.		 */		restrictclauses = group_clauses_by_indexkey(index,													clauses,													outer_clauses,													outer_relids,													&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->ordering[0]);		if (istoplevel && index_is_ordered && !isjoininner)		{			index_pathkeys = build_index_pathkeys(root, index,												  ForwardScanDirection,												  true);			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,									  isjoininner);			result = lappend(result, ipath);		}		/*		 * 4. If the index is ordered, and there is a requested query ordering		 * that we failed to match, consider variant ways of achieving the		 * ordering.  Again, this is only interesting at top level.		 */		if (istoplevel && index_is_ordered && !isjoininner &&			root->query_pathkeys != NIL &&			pathkeys_useful_for_ordering(root, useful_pathkeys) == 0)		{			ScanDirection scandir;			scandir = match_variant_ordering(root, index, restrictclauses);			if (!ScanDirectionIsNoMovement(scandir))			{				ipath = create_index_path(root, index,										  restrictclauses,										  root->query_pathkeys,										  scandir,										  false);				result = lappend(result, ipath);			}		}	}	return result;}/* * generate_bitmap_or_paths *		Look through the list of clauses to find OR clauses, and generate *		a BitmapOrPath for each one we can handle that way.  Return a list *		of the generated BitmapOrPaths. * * outer_clauses is a list of additional clauses that can be assumed true * for the purpose of generating indexquals, but are not to be searched for * ORs.  (See find_usable_indexes() for motivation.) */List *generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,						 List *clauses, List *outer_clauses,						 bool isjoininner,						 Relids outer_relids){	List	   *result = NIL;	List	   *all_clauses;	ListCell   *l;	/*	 * We can use both the current and outer clauses as context for	 * find_usable_indexes	 */	all_clauses = list_concat(list_copy(clauses), outer_clauses);	foreach(l, clauses)	{		RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);		List	   *pathlist;		Path	   *bitmapqual;		ListCell   *j;		Assert(IsA(rinfo, RestrictInfo));		/* Ignore RestrictInfos that aren't ORs */		if (!restriction_is_or_clause(rinfo))			continue;		/*		 * We must be able to match at least one index to each of the arms of

⌨️ 快捷键说明

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