From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 15 Apr 2007 20:09:28 +0000 (+0000)
Subject: Avoid running build_index_pathkeys() in situations where there cannot
X-Git-Tag: REL8_3_BETA1~831
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fa92d21a486de868b21bbc03944649af3e1ac90f;p=postgresql

Avoid running build_index_pathkeys() in situations where there cannot
possibly be any useful pathkeys --- to wit, queries with neither any
join clauses nor any ORDER BY request.  It's nearly free to check for
this case and it saves a useful fraction of the planning time for simple
queries.
---

diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 176f2a6638..243888b58d 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.219 2007/04/06 22:33:42 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.220 2007/04/15 20:09:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -251,6 +251,7 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *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;
@@ -337,7 +338,8 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
 		 * relevant unless we are at top level.
 		 */
 		index_is_ordered = OidIsValid(index->fwdsortop[0]);
-		if (index_is_ordered && istoplevel && outer_rel == NULL)
+		if (index_is_ordered && possibly_useful_pathkeys &&
+			istoplevel && outer_rel == NULL)
 		{
 			index_pathkeys = build_index_pathkeys(root, index,
 												  ForwardScanDirection);
@@ -369,7 +371,8 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
 		 * 4. If the index is ordered, a backwards scan might be
 		 * interesting.  Again, this is only interesting at top level.
 		 */
-		if (index_is_ordered && istoplevel && outer_rel == NULL)
+		if (index_is_ordered && possibly_useful_pathkeys &&
+			istoplevel && outer_rel == NULL)
 		{
 			index_pathkeys = build_index_pathkeys(root, index,
 												  BackwardScanDirection);
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 37c5e35c23..7a2aaa48f6 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.83 2007/01/21 00:57:15 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.84 2007/04/15 20:09:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1327,8 +1327,35 @@ truncate_useless_pathkeys(PlannerInfo *root,
 	 * Note: not safe to modify input list destructively, but we can avoid
 	 * copying the list if we're not actually going to change it
 	 */
-	if (nuseful == list_length(pathkeys))
+	if (nuseful == 0)
+		return NIL;
+	else if (nuseful == list_length(pathkeys))
 		return pathkeys;
 	else
 		return list_truncate(list_copy(pathkeys), nuseful);
 }
+
+/*
+ * has_useful_pathkeys
+ *		Detect whether the specified rel could have any pathkeys that are
+ *		useful according to truncate_useless_pathkeys().
+ *
+ * This is a cheap test that lets us skip building pathkeys at all in very
+ * simple queries.  It's OK to err in the direction of returning "true" when
+ * there really aren't any usable pathkeys, but erring in the other direction
+ * is bad --- so keep this in sync with the routines above!
+ *
+ * We could make the test more complex, for example checking to see if any of
+ * the joinclauses are really mergejoinable, but that likely wouldn't win
+ * often enough to repay the extra cycles.  Queries with neither a join nor
+ * a sort are reasonably common, though, so this much work seems worthwhile.
+ */
+bool
+has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel)
+{
+	if (rel->joininfo != NIL || rel->has_eclass_joins)
+		return true;			/* might be able to use pathkeys for merging */
+	if (root->query_pathkeys != NIL)
+		return true;			/* might be able to use them for ordering */
+	return false;				/* definitely useless */
+}
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 6b985e24cd..c7b8d8c752 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.96 2007/02/16 00:14:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.97 2007/04/15 20:09:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -176,5 +176,6 @@ extern int	pathkeys_useful_for_ordering(PlannerInfo *root, List *pathkeys);
 extern List *truncate_useless_pathkeys(PlannerInfo *root,
 						  RelOptInfo *rel,
 						  List *pathkeys);
+extern bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel);
 
 #endif   /* PATHS_H */