Commit 6161766d authored by Tom Lane's avatar Tom Lane

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.
parent df79b847
...@@ -8,13 +8,14 @@ ...@@ -8,13 +8,14 @@
* *
* *
* IDENTIFICATION * 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 "postgres.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
#include "optimizer/restrictinfo.h" #include "optimizer/restrictinfo.h"
#include "optimizer/var.h" #include "optimizer/var.h"
...@@ -27,7 +28,7 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause, ...@@ -27,7 +28,7 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause,
static Expr *make_sub_restrictinfos(Expr *clause, static Expr *make_sub_restrictinfos(Expr *clause,
bool is_pushed_down, bool is_pushed_down,
bool valid_everywhere); bool valid_everywhere);
static bool join_clause_is_redundant(Query *root, static RestrictInfo *join_clause_is_redundant(Query *root,
RestrictInfo *rinfo, RestrictInfo *rinfo,
List *reference_list, List *reference_list,
JoinType jointype); JoinType jointype);
...@@ -317,17 +318,42 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list, ...@@ -317,17 +318,42 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
{ {
List *result = NIL; List *result = NIL;
List *item; 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) foreach(item, restrictinfo_list)
{ {
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item); RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
RestrictInfo *prevrinfo;
/* drop it if redundant with any prior clause */ /* is it redundant with any prior clause? */
if (join_clause_is_redundant(root, rinfo, result, jointype)) prevrinfo = join_clause_is_redundant(root, rinfo, result, jointype);
continue; if (prevrinfo == NULL)
{
/* otherwise, add it to result list */ /* no, so add it to result list */
result = lappend(result, rinfo); 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; return result;
...@@ -361,7 +387,7 @@ select_nonredundant_join_clauses(Query *root, ...@@ -361,7 +387,7 @@ select_nonredundant_join_clauses(Query *root,
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item); RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
/* drop it if redundant with any reference clause */ /* 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; continue;
/* otherwise, add it to result list */ /* otherwise, add it to result list */
...@@ -373,7 +399,8 @@ select_nonredundant_join_clauses(Query *root, ...@@ -373,7 +399,8 @@ select_nonredundant_join_clauses(Query *root,
/* /*
* join_clause_is_redundant * 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 * This is the guts of both remove_redundant_join_clauses and
* select_nonredundant_join_clauses. See the docs above for motivation. * select_nonredundant_join_clauses. See the docs above for motivation.
...@@ -398,27 +425,30 @@ select_nonredundant_join_clauses(Query *root, ...@@ -398,27 +425,30 @@ select_nonredundant_join_clauses(Query *root,
* then they're not really redundant, because one constrains the * then they're not really redundant, because one constrains the
* joined rows after addition of null fill rows, and the other doesn't. * joined rows after addition of null fill rows, and the other doesn't.
*/ */
static bool static RestrictInfo *
join_clause_is_redundant(Query *root, join_clause_is_redundant(Query *root,
RestrictInfo *rinfo, RestrictInfo *rinfo,
List *reference_list, List *reference_list,
JoinType jointype) JoinType jointype)
{ {
List *refitem;
/* always consider exact duplicates redundant */ /* always consider exact duplicates redundant */
/* XXX would it be sufficient to use ptrMember here? */ foreach(refitem, reference_list)
if (member(rinfo, reference_list)) {
return true; RestrictInfo *refrinfo = (RestrictInfo *) lfirst(refitem);
if (equal(rinfo, refrinfo))
return refrinfo;
}
/* check for redundant merge clauses */ /* check for redundant merge clauses */
if (rinfo->mergejoinoperator != InvalidOid) if (rinfo->mergejoinoperator != InvalidOid)
{ {
bool redundant = false;
List *refitem;
/* do the cheap test first: is it a "var = const" clause? */ /* do the cheap test first: is it a "var = const" clause? */
if (bms_is_empty(rinfo->left_relids) || if (bms_is_empty(rinfo->left_relids) ||
bms_is_empty(rinfo->right_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); cache_mergeclause_pathkeys(root, rinfo);
...@@ -426,21 +456,22 @@ join_clause_is_redundant(Query *root, ...@@ -426,21 +456,22 @@ join_clause_is_redundant(Query *root,
{ {
RestrictInfo *refrinfo = (RestrictInfo *) lfirst(refitem); RestrictInfo *refrinfo = (RestrictInfo *) lfirst(refitem);
if (refrinfo->mergejoinoperator != InvalidOid && 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)))
{ {
redundant = true; cache_mergeclause_pathkeys(root, refrinfo);
break;
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 */ /* otherwise, not redundant */
return false; return NULL;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment