Skip to content

Commit 17b843d

Browse files
committed
Cache eval cost of qualification expressions in RestrictInfo nodes to
avoid repeated evaluations in cost_qual_eval(). This turns out to save a useful fraction of planning time. No change to external representation of RestrictInfo --- although that node type doesn't appear in stored rules anyway.
1 parent 77c443f commit 17b843d

File tree

7 files changed

+54
-24
lines changed

7 files changed

+54
-24
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1994, Regents of the University of California
1616
*
1717
* IDENTIFICATION
18-
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.133 2000/11/24 20:16:39 petere Exp $
18+
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.134 2000/12/12 23:33:32 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -1418,6 +1418,7 @@ _copyRestrictInfo(RestrictInfo *from)
14181418
* ----------------
14191419
*/
14201420
Node_Copy(from, newnode, clause);
1421+
newnode->eval_cost = from->eval_cost;
14211422
newnode->ispusheddown = from->ispusheddown;
14221423
Node_Copy(from, newnode, subclauseindices);
14231424
newnode->mergejoinoperator = from->mergejoinoperator;

src/backend/nodes/equalfuncs.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* Portions Copyright (c) 1994, Regents of the University of California
2121
*
2222
* IDENTIFICATION
23-
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.83 2000/11/24 20:16:39 petere Exp $
23+
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.84 2000/12/12 23:33:33 tgl Exp $
2424
*
2525
*-------------------------------------------------------------------------
2626
*/
@@ -514,6 +514,10 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
514514
{
515515
if (!equal(a->clause, b->clause))
516516
return false;
517+
/*
518+
* ignore eval_cost, since it may not be set yet, and should be
519+
* derivable from the clause anyway
520+
*/
517521
if (a->ispusheddown != b->ispusheddown)
518522
return false;
519523
if (!equal(a->subclauseindices, b->subclauseindices))

src/backend/nodes/readfuncs.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.100 2000/11/12 00:36:57 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.101 2000/12/12 23:33:33 tgl Exp $
1212
*
1313
* NOTES
1414
* Most of the read functions for plan nodes are tested. (In fact, they
@@ -1846,6 +1846,9 @@ _readRestrictInfo(void)
18461846
token = lsptok(NULL, &length); /* now read it */
18471847
local_node->hashjoinoperator = (Oid) atol(token);
18481848

1849+
/* eval_cost is not part of saved representation; compute on first use */
1850+
local_node->eval_cost = -1;
1851+
18491852
return local_node;
18501853
}
18511854

src/backend/optimizer/path/costsize.c

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* Portions Copyright (c) 1994, Regents of the University of California
4343
*
4444
* IDENTIFICATION
45-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.64 2000/10/05 19:48:26 momjian Exp $
45+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.65 2000/12/12 23:33:33 tgl Exp $
4646
*
4747
*-------------------------------------------------------------------------
4848
*/
@@ -672,8 +672,38 @@ Cost
672672
cost_qual_eval(List *quals)
673673
{
674674
Cost total = 0;
675+
List *l;
675676

676-
cost_qual_eval_walker((Node *) quals, &total);
677+
/* We don't charge any cost for the implicit ANDing at top level ... */
678+
679+
foreach(l, quals)
680+
{
681+
Node *qual = (Node *) lfirst(l);
682+
683+
/*
684+
* RestrictInfo nodes contain an eval_cost field reserved for this
685+
* routine's use, so that it's not necessary to evaluate the qual
686+
* clause's cost more than once. If the clause's cost hasn't been
687+
* computed yet, the field will contain -1.
688+
*/
689+
if (qual && IsA(qual, RestrictInfo))
690+
{
691+
RestrictInfo *restrictinfo = (RestrictInfo *) qual;
692+
693+
if (restrictinfo->eval_cost < 0)
694+
{
695+
restrictinfo->eval_cost = 0;
696+
cost_qual_eval_walker((Node *) restrictinfo->clause,
697+
&restrictinfo->eval_cost);
698+
}
699+
total += restrictinfo->eval_cost;
700+
}
701+
else
702+
{
703+
/* If it's a bare expression, must always do it the hard way */
704+
cost_qual_eval_walker(qual, &total);
705+
}
706+
}
677707
return total;
678708
}
679709

@@ -748,18 +778,6 @@ cost_qual_eval_walker(Node *node, Cost *total)
748778
}
749779
/* fall through to examine args of Expr node */
750780
}
751-
752-
/*
753-
* expression_tree_walker doesn't know what to do with RestrictInfo
754-
* nodes, but we just want to recurse through them.
755-
*/
756-
if (IsA(node, RestrictInfo))
757-
{
758-
RestrictInfo *restrictinfo = (RestrictInfo *) node;
759-
760-
return cost_qual_eval_walker((Node *) restrictinfo->clause, total);
761-
}
762-
/* Otherwise, recurse. */
763781
return expression_tree_walker(node, cost_qual_eval_walker,
764782
(void *) total);
765783
}

src/backend/optimizer/plan/initsplan.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.53 2000/11/23 03:57:31 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.54 2000/12/12 23:33:33 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -338,6 +338,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
338338
bool can_be_equijoin;
339339

340340
restrictinfo->clause = (Expr *) clause;
341+
restrictinfo->eval_cost = -1; /* not computed until needed */
341342
restrictinfo->subclauseindices = NIL;
342343
restrictinfo->mergejoinoperator = InvalidOid;
343344
restrictinfo->left_sortop = InvalidOid;

src/backend/optimizer/prep/prepunion.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
*
1616
* IDENTIFICATION
17-
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.56 2000/11/12 00:36:59 tgl Exp $
17+
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.57 2000/12/12 23:33:34 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -652,7 +652,7 @@ adjust_inherited_attrs_mutator(Node *node,
652652
/*
653653
* We have to process RestrictInfo nodes specially: we do NOT want to
654654
* copy the original subclauseindices list, since the new rel may have
655-
* different indices. The list will be rebuilt during planning anyway.
655+
* different indices. The list will be rebuilt during later planning.
656656
*/
657657
if (IsA(node, RestrictInfo))
658658
{
@@ -666,6 +666,7 @@ adjust_inherited_attrs_mutator(Node *node,
666666
adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
667667

668668
newinfo->subclauseindices = NIL;
669+
newinfo->eval_cost = -1; /* reset this too */
669670

670671
return (Node *) newinfo;
671672
}

src/include/nodes/relation.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: relation.h,v 1.50 2000/11/12 00:37:01 tgl Exp $
10+
* $Id: relation.h,v 1.51 2000/12/12 23:33:32 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -373,9 +373,9 @@ typedef JoinPath NestPath;
373373
* A mergejoin path has these fields.
374374
*
375375
* path_mergeclauses lists the clauses (in the form of RestrictInfos)
376-
* that will be used in the merge. (Before 7.0, this was a list of
377-
* bare clause expressions, but we can save on list memory by leaving
378-
* it in the form of a RestrictInfo list.)
376+
* that will be used in the merge. (Before 7.0, this was a list of bare
377+
* clause expressions, but we can save on list memory and cost_qual_eval
378+
* work by leaving it in the form of a RestrictInfo list.)
379379
*
380380
* Note that the mergeclauses are a subset of the parent relation's
381381
* restriction-clause list. Any join clauses that are not mergejoinable
@@ -491,6 +491,8 @@ typedef struct RestrictInfo
491491

492492
Expr *clause; /* the represented clause of WHERE or JOIN */
493493

494+
Cost eval_cost; /* eval cost of clause; -1 if not yet set */
495+
494496
bool ispusheddown; /* TRUE if clause was pushed down in level */
495497

496498
/* only used if clause is an OR clause: */

0 commit comments

Comments
 (0)