Make EXPLAIN results for Append, Group, Agg, Unique nodes more plausible.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 3 Feb 2000 06:12:19 +0000 (06:12 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 3 Feb 2000 06:12:19 +0000 (06:12 +0000)
Group and Unique use an arbitrary assumption that there will be about
10% as many groups as input tuples --- perhaps someday we can refine this.

src/backend/optimizer/plan/createplan.c
src/backend/optimizer/prep/prepunion.c

index 70a73821641bebd691293fa9fd00e220b3c2b168..69c0a3f65be8bd0e454c253443a8b8daac54e4e2 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.82 2000/01/27 18:11:30 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.83 2000/02/03 06:12:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -743,9 +743,9 @@ create_hashjoin_node(HashPath *best_path,
  * * Var nodes representing index keys must have varattno equal to the
  *   index's attribute number, not the attribute number in the original rel.
  * * indxpath.c may have selected an index that is binary-compatible with
- *   the actual expression operator, but not the same; we must replace the
- *   expression's operator with the binary-compatible equivalent operator
- *   that the index will recognize.
+ *   the actual expression operator, but not exactly the same datatype.
+ *   We must replace the expression's operator with the binary-compatible
+ *   equivalent operator that the index will recognize.
  * * If the index key is on the right, commute the clause to put it on the
  *   left.  (Someday the executor might not need this, but for now it does.)
  *
@@ -1054,6 +1054,7 @@ copy_path_costsize(Plan *dest, Path *src)
  * Copy cost and size info from a lower plan node to an inserted node.
  * This is not critical, since the decisions have already been made,
  * but it helps produce more reasonable-looking EXPLAIN output.
+ * (Some callers alter the info after copying it.)
  */
 static void
 copy_plan_costsize(Plan *dest, Plan *src)
@@ -1178,12 +1179,7 @@ make_nestloop(List *qptlist,
    NestLoop   *node = makeNode(NestLoop);
    Plan       *plan = &node->join;
 
-   /*
-    * this cost estimate is entirely bogus... hopefully it will be
-    * overwritten by caller.
-    */
-   plan->cost = (lefttree ? lefttree->cost : 0) +
-       (righttree ? righttree->cost : 0);
+   /* cost should be inserted by caller */
    plan->state = (EState *) NULL;
    plan->targetlist = qptlist;
    plan->qual = qpqual;
@@ -1204,12 +1200,7 @@ make_hashjoin(List *tlist,
    HashJoin   *node = makeNode(HashJoin);
    Plan       *plan = &node->join;
 
-   /*
-    * this cost estimate is entirely bogus... hopefully it will be
-    * overwritten by caller.
-    */
-   plan->cost = (lefttree ? lefttree->cost : 0) +
-       (righttree ? righttree->cost : 0);
+   /* cost should be inserted by caller */
    plan->state = (EState *) NULL;
    plan->targetlist = tlist;
    plan->qual = qpqual;
@@ -1248,12 +1239,7 @@ make_mergejoin(List *tlist,
    MergeJoin  *node = makeNode(MergeJoin);
    Plan       *plan = &node->join;
 
-   /*
-    * this cost estimate is entirely bogus... hopefully it will be
-    * overwritten by caller.
-    */
-   plan->cost = (lefttree ? lefttree->cost : 0) +
-       (righttree ? righttree->cost : 0);
+   /* cost should be inserted by caller */
    plan->state = (EState *) NULL;
    plan->targetlist = tlist;
    plan->qual = qpqual;
@@ -1293,6 +1279,7 @@ make_material(List *tlist,
    Plan       *plan = &node->plan;
 
    copy_plan_costsize(plan, lefttree);
+   /* XXX shouldn't we charge some additional cost for materialization? */
    plan->state = (EState *) NULL;
    plan->targetlist = tlist;
    plan->qual = NIL;
@@ -1310,6 +1297,20 @@ make_agg(List *tlist, Plan *lefttree)
    Agg        *node = makeNode(Agg);
 
    copy_plan_costsize(&node->plan, lefttree);
+   /*
+    * The tuple width from the input node is OK, as is the cost (we are
+    * ignoring the cost of computing the aggregate; is there any value
+    * in accounting for it?).  But the tuple count is bogus.  We will
+    * produce a single tuple if the input is not a Group, and a tuple
+    * per group otherwise.  For now, estimate the number of groups as
+    * 10% of the number of tuples --- bogus, but how to do better?
+    * (Note we assume the input Group node is in "tuplePerGroup" mode,
+    * so it didn't reduce its row count already.)
+    */
+   if (IsA(lefttree, Group))
+       node->plan.plan_rows *= 0.1;
+   else
+       node->plan.plan_rows = 1;
    node->plan.state = (EState *) NULL;
    node->plan.qual = NULL;
    node->plan.targetlist = tlist;
@@ -1329,6 +1330,15 @@ make_group(List *tlist,
    Group      *node = makeNode(Group);
 
    copy_plan_costsize(&node->plan, lefttree);
+   /*
+    * If tuplePerGroup (which is named exactly backwards) is true,
+    * we will return all the input tuples, so the input node's row count
+    * is OK.  Otherwise, we'll return only one tuple from each group.
+    * For now, estimate the number of groups as 10% of the number of
+    * tuples --- bogus, but how to do better?
+    */
+   if (! tuplePerGroup)
+       node->plan.plan_rows *= 0.1;
    node->plan.state = (EState *) NULL;
    node->plan.qual = NULL;
    node->plan.targetlist = tlist;
@@ -1357,6 +1367,11 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
    List       *slitem;
 
    copy_plan_costsize(plan, lefttree);
+   /*
+    * As for Group, we make the unsupported assumption that there will be
+    * 10% as many tuples out as in.
+    */
+   plan->plan_rows *= 0.1;
    plan->state = (EState *) NULL;
    plan->targetlist = tlist;
    plan->qual = NIL;
index 4323b652e8d8a8fd2844c902ba4d1d0a2021b8a0..95005f166f164187d44e3c547b8ae70d2b664971 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.42 2000/01/27 18:11:32 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.43 2000/02/03 06:12:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -218,11 +218,11 @@ plan_union_queries(Query *parse)
    parse->havingQual = NULL;
    parse->hasAggs = false;
 
-   return (make_append(union_plans,
-                       union_rts,
-                       0,
-                       NULL,
-                       parse->targetList));
+   return make_append(union_plans,
+                      union_rts,
+                      0,
+                      NULL,
+                      parse->targetList);
 }
 
 
@@ -272,11 +272,11 @@ plan_inherit_queries(Query *parse, List *tlist, Index rt_index)
    union_plans = plan_inherit_query(union_relids, rt_index, rt_entry,
                                     parse, tlist, &inheritrtable);
 
-   return (make_append(union_plans,
-                       NULL,
-                       rt_index,
-                       inheritrtable,
-                       ((Plan *) lfirst(union_plans))->targetlist));
+   return make_append(union_plans,
+                      NULL,
+                      rt_index,
+                      inheritrtable,
+                      ((Plan *) lfirst(union_plans))->targetlist);
 }
 
 /*
@@ -551,9 +551,18 @@ make_append(List *appendplans,
    node->unionrtables = unionrtables;
    node->inheritrelid = rt_index;
    node->inheritrtable = inheritrtable;
-   node->plan.cost = 0.0;
+   node->plan.cost = 0;
+   node->plan.plan_rows = 0;
+   node->plan.plan_width = 0;
    foreach(subnode, appendplans)
-       node->plan.cost += ((Plan *) lfirst(subnode))->cost;
+   {
+       Plan   *subplan = (Plan *) lfirst(subnode);
+
+       node->plan.cost += subplan->cost;
+       node->plan.plan_rows += subplan->plan_rows;
+       if (node->plan.plan_width < subplan->plan_width)
+           node->plan.plan_width = subplan->plan_width;
+   }
    node->plan.state = (EState *) NULL;
    node->plan.targetlist = tlist;
    node->plan.qual = NIL;