From 6161766daf7fe49647538aedbbfbdb98406fca3d Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 27 Feb 2004 21:48:04 +0000
Subject: [PATCH] Adjust remove_redundant_join_clauses() so that when it has a
 choice of which redundant clause to remove, it removes the more expensive
 one. In simple scenarios the clauses will be like 'var = var' and there's no
 difference, but we are now capable of considering cases where there are
 sub-selects in the clauses, and it makes a BIG difference.

---
 src/backend/optimizer/util/restrictinfo.c | 89 +++++++++++++++--------
 1 file changed, 60 insertions(+), 29 deletions(-)

diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index e2cc53cc692..ddf965fdf2b 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -8,13 +8,14 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.25 2004/01/05 23:39:54 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.26 2004/02/27 21:48:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "optimizer/clauses.h"
+#include "optimizer/cost.h"
 #include "optimizer/paths.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
@@ -27,7 +28,7 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause,
 static Expr *make_sub_restrictinfos(Expr *clause,
 									bool is_pushed_down,
 									bool valid_everywhere);
-static bool join_clause_is_redundant(Query *root,
+static RestrictInfo *join_clause_is_redundant(Query *root,
 						 RestrictInfo *rinfo,
 						 List *reference_list,
 						 JoinType jointype);
@@ -317,17 +318,42 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
 {
 	List	   *result = NIL;
 	List	   *item;
+	QualCost	cost;
+
+	/*
+	 * If there are any redundant clauses, we want to eliminate the ones
+	 * that are more expensive in favor of the ones that are less so.
+	 * Run cost_qual_eval() to ensure the eval_cost fields are set up.
+	 */
+	cost_qual_eval(&cost, restrictinfo_list);
+
+	/*
+	 * We don't have enough knowledge yet to be able to estimate the number
+	 * of times a clause might be evaluated, so it's hard to weight the
+	 * startup and per-tuple costs appropriately.  For now just weight 'em
+	 * the same.
+	 */
+#define CLAUSECOST(r)  ((r)->eval_cost.startup + (r)->eval_cost.per_tuple)
 
 	foreach(item, restrictinfo_list)
 	{
 		RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
+		RestrictInfo *prevrinfo;
 
-		/* drop it if redundant with any prior clause */
-		if (join_clause_is_redundant(root, rinfo, result, jointype))
-			continue;
-
-		/* otherwise, add it to result list */
-		result = lappend(result, rinfo);
+		/* is it redundant with any prior clause? */
+		prevrinfo = join_clause_is_redundant(root, rinfo, result, jointype);
+		if (prevrinfo == NULL)
+		{
+			/* no, so add it to result list */
+			result = lappend(result, rinfo);
+		}
+		else if (CLAUSECOST(rinfo) < CLAUSECOST(prevrinfo))
+		{
+			/* keep this one, drop the previous one */
+			result = lremove(prevrinfo, result);
+			result = lappend(result, rinfo);
+		}
+		/* else, drop this one */
 	}
 
 	return result;
@@ -361,7 +387,7 @@ select_nonredundant_join_clauses(Query *root,
 		RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
 
 		/* drop it if redundant with any reference clause */
-		if (join_clause_is_redundant(root, rinfo, reference_list, jointype))
+		if (join_clause_is_redundant(root, rinfo, reference_list, jointype) != NULL)
 			continue;
 
 		/* otherwise, add it to result list */
@@ -373,7 +399,8 @@ select_nonredundant_join_clauses(Query *root,
 
 /*
  * join_clause_is_redundant
- *		Returns true if rinfo is redundant with any clause in reference_list.
+ *		If rinfo is redundant with any clause in reference_list,
+ *		return one such clause; otherwise return NULL.
  *
  * This is the guts of both remove_redundant_join_clauses and
  * select_nonredundant_join_clauses.  See the docs above for motivation.
@@ -398,27 +425,30 @@ select_nonredundant_join_clauses(Query *root,
  * then they're not really redundant, because one constrains the
  * joined rows after addition of null fill rows, and the other doesn't.
  */
-static bool
+static RestrictInfo *
 join_clause_is_redundant(Query *root,
 						 RestrictInfo *rinfo,
 						 List *reference_list,
 						 JoinType jointype)
 {
+	List	   *refitem;
+
 	/* always consider exact duplicates redundant */
-	/* XXX would it be sufficient to use ptrMember here? */
-	if (member(rinfo, reference_list))
-		return true;
+	foreach(refitem, reference_list)
+	{
+		RestrictInfo *refrinfo = (RestrictInfo *) lfirst(refitem);
+
+		if (equal(rinfo, refrinfo))
+			return refrinfo;
+	}
 
 	/* check for redundant merge clauses */
 	if (rinfo->mergejoinoperator != InvalidOid)
 	{
-		bool		redundant = false;
-		List	   *refitem;
-
 		/* do the cheap test first: is it a "var = const" clause? */
 		if (bms_is_empty(rinfo->left_relids) ||
 			bms_is_empty(rinfo->right_relids))
-			return false;		/* var = const, so not redundant */
+			return NULL;		/* var = const, so not redundant */
 
 		cache_mergeclause_pathkeys(root, rinfo);
 
@@ -426,21 +456,22 @@ join_clause_is_redundant(Query *root,
 		{
 			RestrictInfo *refrinfo = (RestrictInfo *) lfirst(refitem);
 
-			if (refrinfo->mergejoinoperator != InvalidOid &&
-				rinfo->left_pathkey == refrinfo->left_pathkey &&
-				rinfo->right_pathkey == refrinfo->right_pathkey &&
-				(rinfo->is_pushed_down == refrinfo->is_pushed_down ||
-				 !IS_OUTER_JOIN(jointype)))
+			if (refrinfo->mergejoinoperator != InvalidOid)
 			{
-				redundant = true;
-				break;
+				cache_mergeclause_pathkeys(root, refrinfo);
+
+				if (rinfo->left_pathkey == refrinfo->left_pathkey &&
+					rinfo->right_pathkey == refrinfo->right_pathkey &&
+					(rinfo->is_pushed_down == refrinfo->is_pushed_down ||
+					 !IS_OUTER_JOIN(jointype)))
+				{
+					/* Yup, it's redundant */
+					return refrinfo;
+				}
 			}
 		}
-
-		if (redundant)
-			return true;		/* var = var, so redundant */
 	}
 
 	/* otherwise, not redundant */
-	return false;
+	return NULL;
 }
-- 
GitLab