88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.25 2004/01/05 23:39:54 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.26 2004/02/27 21:48:04 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
1515#include "postgres.h"
1616
1717#include "optimizer/clauses.h"
18+ #include "optimizer/cost.h"
1819#include "optimizer/paths.h"
1920#include "optimizer/restrictinfo.h"
2021#include "optimizer/var.h"
@@ -27,7 +28,7 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause,
2728static Expr * make_sub_restrictinfos (Expr * clause ,
2829 bool is_pushed_down ,
2930 bool valid_everywhere );
30- static bool join_clause_is_redundant (Query * root ,
31+ static RestrictInfo * join_clause_is_redundant (Query * root ,
3132 RestrictInfo * rinfo ,
3233 List * reference_list ,
3334 JoinType jointype );
@@ -317,17 +318,42 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
317318{
318319 List * result = NIL ;
319320 List * item ;
321+ QualCost cost ;
322+
323+ /*
324+ * If there are any redundant clauses, we want to eliminate the ones
325+ * that are more expensive in favor of the ones that are less so.
326+ * Run cost_qual_eval() to ensure the eval_cost fields are set up.
327+ */
328+ cost_qual_eval (& cost , restrictinfo_list );
329+
330+ /*
331+ * We don't have enough knowledge yet to be able to estimate the number
332+ * of times a clause might be evaluated,
8000
so it's hard to weight the
333+ * startup and per-tuple costs appropriately. For now just weight 'em
334+ * the same.
335+ */
336+ #define CLAUSECOST (r ) ((r)->eval_cost.startup + (r)->eval_cost.per_tuple)
320337
321338 foreach (item , restrictinfo_list )
322339 {
323340 RestrictInfo * rinfo = (RestrictInfo * ) lfirst (item );
341+ RestrictInfo * prevrinfo ;
324342
325- /* drop it if redundant with any prior clause */
326- if (join_clause_is_redundant (root , rinfo , result , jointype ))
327- continue ;
328-
329- /* otherwise, add it to result list */
330- result = lappend (result , rinfo );
343+ /* is it redundant with any prior clause? */
344+ prevrinfo = join_clause_is_redundant (root , rinfo , result , jointype );
345+ if (prevrinfo == NULL )
346+ {
347+ /* no, so add it to result list */
348+ result = lappend (result , rinfo );
349+ }
350+ else if (CLAUSECOST (rinfo ) < CLAUSECOST (prevrinfo ))
351+ {
352+ /* keep this one, drop the previous one */
353+ result = lremove (prevrinfo , result );
354+ result = lappend (result , rinfo );
355+ }
356+ /* else, drop this one */
331357 }
332358
333359 return result ;
@@ -361,7 +387,7 @@ select_nonredundant_join_clauses(Query *root,
361387 RestrictInfo * rinfo = (RestrictInfo * ) lfirst (item );
362388
363389 /* drop it if redundant with any reference clause */
364- if (join_clause_is_redundant (root , rinfo , reference_list , jointype ))
390+ if (join_clause_is_redundant (root , rinfo , reference_list , jointype ) != NULL )
365391 continue ;
366392
367393 /* otherwise, add it to result list */
@@ -373,7 +399,8 @@ select_nonredundant_join_clauses(Query *root,
373399
374400/*
375401 * join_clause_is_redundant
376- * Returns true if rinfo is redundant with any clause in reference_list.
402+ * If rinfo is redundant with any clause in reference_list,
403+ * return one such clause; otherwise return NULL.
377404 *
378405 * This is the guts of both remove_redundant_join_clauses and
379406 * select_nonredundant_join_clauses. See the docs above for motivation.
@@ -398,49 +425,53 @@ select_nonredundant_join_clauses(Query *root,
398425 * then they're not really redundant, because one constrains the
399426 * joined rows after addition of null fill rows, and the other doesn't.
400427 */
401- static bool
428+ static RestrictInfo *
402429join_clause_is_redundant (Query * root ,
403430 RestrictInfo * rinfo ,
404431 List * reference_list ,
405432 JoinType jointype )
406433{
434+ List * refitem ;
435+
407436 /* always consider exact duplicates redundant */
408- /* XXX would it be sufficient to use ptrMember here? */
409- if (member (rinfo , reference_list ))
410- return true;
437+ foreach (refitem , reference_list )
438+ {
439+ RestrictInfo * refrinfo = (RestrictInfo * ) lfirst (refitem );
440+
441+ if (equal (rinfo , refrinfo ))
442+ return refrinfo ;
443+ }
411444
412445 /* check for redundant merge clauses */
413446 if (rinfo -> mergejoinoperator != InvalidOid )
414447 {
415- bool redundant = false;
416- List * refitem ;
417-
418448 /* do the cheap test first: is it a "var = const" clause? */
419449 if (bms_is_empty (rinfo -> left_relids ) ||
420450 bms_is_empty (rinfo -> right_relids ))
421- return false ; /* var = const, so not redundant */
451+ return NULL ; /* var = const, so not redundant */
422452
423453 cache_mergeclause_pathkeys (root , rinfo );
424454
425455 foreach (refitem , reference_list )
426456 {
427457 RestrictInfo * refrinfo = (RestrictInfo * ) lfirst (refitem );
428458
429- if (refrinfo -> mergejoinoperator != InvalidOid &&
430- rinfo -> left_pathkey == refrinfo -> left_pathkey &&
431- rinfo -> right_pathkey == refrinfo -> right_pathkey &&
432- (rinfo -> is_pushed_down == refrinfo -> is_pushed_down ||
433- !IS_OUTER_JOIN (jointype )))
459+ if (refrinfo -> mergejoinoperator != InvalidOid )
434460 {
435- redundant = true;
436- break ;
461+ cache_mergeclause_pathkeys (root , refrinfo );
462+
463+ if (rinfo -> left_pathkey == refrinfo -> left_pathkey &&
464+ rinfo -> right_pathkey == refrinfo -> right_pathkey &&
465+ (rinfo -> is_pushed_down == refrinfo -> is_pushed_down ||
466+ !IS_OUTER_JOIN (jointype )))
467+ {
468+ /* Yup, it's redundant */
469+ return refrinfo ;
470+ }
437471 }
438472 }
439-
440- if (redundant )
441- return true; /* var = var, so redundant */
442473 }
443474
444475 /* otherwise, not redundant */
445- return false ;
476+ return NULL ;
446477}
0 commit comments