From 17b843d67718a716c1abb4afd2abf8a5edba9f32 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Tue, 12 Dec 2000 23:33:34 +0000 Subject: [PATCH] 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. --- src/backend/nodes/copyfuncs.c | 3 +- src/backend/nodes/equalfuncs.c | 6 +++- src/backend/nodes/readfuncs.c | 5 ++- src/backend/optimizer/path/costsize.c | 46 ++++++++++++++++++-------- src/backend/optimizer/plan/initsplan.c | 3 +- src/backend/optimizer/prep/prepunion.c | 5 +-- src/include/nodes/relation.h | 10 +++--- 7 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 1e03e04418..3e4a6d91dd 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.133 2000/11/24 20:16:39 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.134 2000/12/12 23:33:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1418,6 +1418,7 @@ _copyRestrictInfo(RestrictInfo *from) * ---------------- */ Node_Copy(from, newnode, clause); + newnode->eval_cost = from->eval_cost; newnode->ispusheddown = from->ispusheddown; Node_Copy(from, newnode, subclauseindices); newnode->mergejoinoperator = from->mergejoinoperator; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 51dbd24976..2f6a93b95b 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -20,7 +20,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.83 2000/11/24 20:16:39 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.84 2000/12/12 23:33:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -514,6 +514,10 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) { if (!equal(a->clause, b->clause)) return false; + /* + * ignore eval_cost, since it may not be set yet, and should be + * derivable from the clause anyway + */ if (a->ispusheddown != b->ispusheddown) return false; if (!equal(a->subclauseindices, b->subclauseindices)) diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 6a6dce48bf..d8aa2a5d2d 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.100 2000/11/12 00:36:57 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.101 2000/12/12 23:33:33 tgl Exp $ * * NOTES * Most of the read functions for plan nodes are tested. (In fact, they @@ -1846,6 +1846,9 @@ _readRestrictInfo(void) token = lsptok(NULL, &length); /* now read it */ local_node->hashjoinoperator = (Oid) atol(token); + /* eval_cost is not part of saved representation; compute on first use */ + local_node->eval_cost = -1; + return local_node; } diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 8251b8d451..c19ae3883d 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -42,7 +42,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.64 2000/10/05 19:48:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.65 2000/12/12 23:33:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -672,8 +672,38 @@ Cost cost_qual_eval(List *quals) { Cost total = 0; + List *l; - cost_qual_eval_walker((Node *) quals, &total); + /* We don't charge any cost for the implicit ANDing at top level ... */ + + foreach(l, quals) + { + Node *qual = (Node *) lfirst(l); + + /* + * RestrictInfo nodes contain an eval_cost field reserved for this + * routine's use, so that it's not necessary to evaluate the qual + * clause's cost more than once. If the clause's cost hasn't been + * computed yet, the field will contain -1. + */ + if (qual && IsA(qual, RestrictInfo)) + { + RestrictInfo *restrictinfo = (RestrictInfo *) qual; + + if (restrictinfo->eval_cost < 0) + { + restrictinfo->eval_cost = 0; + cost_qual_eval_walker((Node *) restrictinfo->clause, + &restrictinfo->eval_cost); + } + total += restrictinfo->eval_cost; + } + else + { + /* If it's a bare expression, must always do it the hard way */ + cost_qual_eval_walker(qual, &total); + } + } return total; } @@ -748,18 +778,6 @@ cost_qual_eval_walker(Node *node, Cost *total) } /* fall through to examine args of Expr node */ } - - /* - * expression_tree_walker doesn't know what to do with RestrictInfo - * nodes, but we just want to recurse through them. - */ - if (IsA(node, RestrictInfo)) - { - RestrictInfo *restrictinfo = (RestrictInfo *) node; - - return cost_qual_eval_walker((Node *) restrictinfo->clause, total); - } - /* Otherwise, recurse. */ return expression_tree_walker(node, cost_qual_eval_walker, (void *) total); } diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index ee037c750b..12698f5e5f 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.53 2000/11/23 03:57:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.54 2000/12/12 23:33:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -338,6 +338,7 @@ distribute_qual_to_rels(Query *root, Node *clause, bool can_be_equijoin; restrictinfo->clause = (Expr *) clause; + restrictinfo->eval_cost = -1; /* not computed until needed */ restrictinfo->subclauseindices = NIL; restrictinfo->mergejoinoperator = InvalidOid; restrictinfo->left_sortop = InvalidOid; diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index ebb09f5939..d52ed8fb92 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.56 2000/11/12 00:36:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.57 2000/12/12 23:33:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -652,7 +652,7 @@ adjust_inherited_attrs_mutator(Node *node, /* * We have to process RestrictInfo nodes specially: we do NOT want to * copy the original subclauseindices list, since the new rel may have - * different indices. The list will be rebuilt during planning anyway. + * different indices. The list will be rebuilt during later planning. */ if (IsA(node, RestrictInfo)) { @@ -666,6 +666,7 @@ adjust_inherited_attrs_mutator(Node *node, adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context); newinfo->subclauseindices = NIL; + newinfo->eval_cost = -1; /* reset this too */ return (Node *) newinfo; } diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 45d53be5f6..366392df0d 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: relation.h,v 1.50 2000/11/12 00:37:01 tgl Exp $ + * $Id: relation.h,v 1.51 2000/12/12 23:33:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -373,9 +373,9 @@ typedef JoinPath NestPath; * A mergejoin path has these fields. * * path_mergeclauses lists the clauses (in the form of RestrictInfos) - * that will be used in the merge. (Before 7.0, this was a list of - * bare clause expressions, but we can save on list memory by leaving - * it in the form of a RestrictInfo list.) + * that will be used in the merge. (Before 7.0, this was a list of bare + * clause expressions, but we can save on list memory and cost_qual_eval + * work by leaving it in the form of a RestrictInfo list.) * * Note that the mergeclauses are a subset of the parent relation's * restriction-clause list. Any join clauses that are not mergejoinable @@ -491,6 +491,8 @@ typedef struct RestrictInfo Expr *clause; /* the represented clause of WHERE or JOIN */ + Cost eval_cost; /* eval cost of clause; -1 if not yet set */ + bool ispusheddown; /* TRUE if clause was pushed down in level */ /* only used if clause is an OR clause: */ -- 2.40.0