OSDN Git Service

Planner wasn't correctly handling adjustment of tuple_fraction for the
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 1 Apr 2001 22:37:19 +0000 (22:37 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 1 Apr 2001 22:37:19 +0000 (22:37 +0000)
case of LIMIT in a sub-select.

src/backend/optimizer/plan/planner.c

index c5bd439..199d279 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.102 2001/03/22 03:59:37 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.103 2001/04/01 22:37:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -874,9 +874,9 @@ grouping_planner(Query *parse, double tuple_fraction)
 
                /*
                 * Figure out whether we expect to retrieve all the tuples that
-                * the plan can generate, or to stop early due to a LIMIT or other
-                * factors.  If the caller passed a value >= 0, believe that
-                * value, else do our own examination of the query context.
+                * the plan can generate, or to stop early due to outside factors
+                * such as a cursor.  If the caller passed a value >= 0, believe
+                * that value, else do our own examination of the query context.
                 */
                if (tuple_fraction < 0.0)
                {
@@ -884,74 +884,118 @@ grouping_planner(Query *parse, double tuple_fraction)
                        tuple_fraction = 0.0;
 
                        /*
-                        * Check for a LIMIT clause.
+                        * Check for retrieve-into-portal, ie DECLARE CURSOR.
+                        *
+                        * We have no real idea how many tuples the user will ultimately
+                        * FETCH from a cursor, but it seems a good bet that he
+                        * doesn't want 'em all.  Optimize for 10% retrieval (you
+                        * gotta better number?  Should this be a SETtable parameter?)
+                        */
+                       if (parse->isPortal)
+                               tuple_fraction = 0.10;
+               }
+
+               /*
+                * Adjust tuple_fraction if we see that we are going to apply
+                * limiting/grouping/aggregation/etc.  This is not overridable by
+                * the caller, since it reflects plan actions that this routine
+                * will certainly take, not assumptions about context.
+                */
+               if (parse->limitCount != NULL)
+               {
+                       /*
+                        * A LIMIT clause limits the absolute number of tuples returned.
+                        * However, if it's not a constant LIMIT then we have to punt;
+                        * for lack of a better idea, assume 10% of the plan's result
+                        * is wanted.
                         */
-                       if (parse->limitCount != NULL)
+                       double  limit_fraction = 0.0;
+
+                       if (IsA(parse->limitCount, Const))
                        {
-                               if (IsA(parse->limitCount, Const))
+                               Const      *limitc = (Const *) parse->limitCount;
+                               int32           count = DatumGetInt32(limitc->constvalue);
+
+                               /*
+                                * A NULL-constant LIMIT represents "LIMIT ALL", which
+                                * we treat the same as no limit (ie, expect to
+                                * retrieve all the tuples).
+                                */
+                               if (!limitc->constisnull && count > 0)
                                {
-                                       Const      *limitc = (Const *) parse->limitCount;
-                                       int32           count = DatumGetInt32(limitc->constvalue);
-
-                                       /*
-                                        * A NULL-constant LIMIT represents "LIMIT ALL", which
-                                        * we treat the same as no limit (ie, expect to
-                                        * retrieve all the tuples).
-                                        */
-                                       if (!limitc->constisnull && count > 0)
+                                       limit_fraction = (double) count;
+                                       /* We must also consider the OFFSET, if present */
+                                       if (parse->limitOffset != NULL)
                                        {
-                                               tuple_fraction = (double) count;
-                                               /* We must also consider the OFFSET, if present */
-                                               if (parse->limitOffset != NULL)
+                                               if (IsA(parse->limitOffset, Const))
+                                               {
+                                                       int32           offset;
+
+                                                       limitc = (Const *) parse->limitOffset;
+                                                       offset = DatumGetInt32(limitc->constvalue);
+                                                       if (!limitc->constisnull && offset > 0)
+                                                               limit_fraction += (double) offset;
+                                               }
+                                               else
                                                {
-                                                       if (IsA(parse->limitOffset, Const))
-                                                       {
-                                                               int32           offset;
-
-                                                               limitc = (Const *) parse->limitOffset;
-                                                               offset = DatumGetInt32(limitc->constvalue);
-                                                               if (!limitc->constisnull && offset > 0)
-                                                                       tuple_fraction += (double) offset;
-                                                       }
-                                                       else
-                                                       {
-                                                               /* It's an expression ... punt ... */
-                                                               tuple_fraction = 0.10;
-                                                       }
+                                                       /* OFFSET is an expression ... punt ... */
+                                                       limit_fraction = 0.10;
                                                }
                                        }
                                }
+                       }
+                       else
+                       {
+                               /* LIMIT is an expression ... punt ... */
+                               limit_fraction = 0.10;
+                       }
+
+                       if (limit_fraction > 0.0)
+                       {
+                               /*
+                                * If we have absolute limits from both caller and LIMIT,
+                                * use the smaller value; if one is fractional and the other
+                                * absolute, treat the fraction as a fraction of the absolute
+                                * value; else we can multiply the two fractions together.
+                                */
+                               if (tuple_fraction >= 1.0)
+                               {
+                                       if (limit_fraction >= 1.0)
+                                       {
+                                               /* both absolute */
+                                               tuple_fraction = Min(tuple_fraction, limit_fraction);
+                                       }
+                                       else
+                                       {
+                                               /* caller absolute, limit fractional */
+                                               tuple_fraction *= limit_fraction;
+                                               if (tuple_fraction < 1.0)
+                                                       tuple_fraction = 1.0;
+                                       }
+                               }
+                               else if (tuple_fraction > 0.0)
+                               {
+                                       if (limit_fraction >= 1.0)
+                                       {
+                                               /* caller fractional, limit absolute */
+                                               tuple_fraction *= limit_fraction;
+                                               if (tuple_fraction < 1.0)
+                                                       tuple_fraction = 1.0;
+                                       }
+                                       else
+                                       {
+                                               /* both fractional */
+                                               tuple_fraction *= limit_fraction;
+                                       }
+                               }
                                else
                                {
-
-                                       /*
-                                        * COUNT is an expression ... don't know exactly what
-                                        * the limit will be, but for lack of a better idea
-                                        * assume 10% of the plan's result is wanted.
-                                        */
-                                       tuple_fraction = 0.10;
+                                       /* no info from caller, just use limit */
+                                       tuple_fraction = limit_fraction;
                                }
                        }
-
-                       /*
-                        * If no LIMIT, check for retrieve-into-portal, ie DECLARE
-                        * CURSOR.
-                        *
-                        * We have no real idea how many tuples the user will ultimately
-                        * FETCH from a cursor, but it seems a good bet that he
-                        * doesn't want 'em all.  Optimize for 10% retrieval (you
-                        * gotta better number?)
-                        */
-                       else if (parse->isPortal)
-                               tuple_fraction = 0.10;
                }
 
-               /*
-                * Adjust tuple_fraction if we see that we are going to apply
-                * grouping/aggregation/etc.  This is not overridable by the
-                * caller, since it reflects plan actions that this routine will
-                * certainly take, not assumptions about context.
-                */
                if (parse->groupClause)
                {