OSDN Git Service

Apply the "nodeAgg" optimization to more of the builtin transition
authorNeil Conway <neilc@samurai.com>
Wed, 6 Apr 2005 23:56:07 +0000 (23:56 +0000)
committerNeil Conway <neilc@samurai.com>
Wed, 6 Apr 2005 23:56:07 +0000 (23:56 +0000)
functions. This patch optimizes int2_sum(), int4_sum(), float4_accum()
and float8_accum() to avoid needing to copy the transition function's
state for each input tuple of the aggregate. In an extreme case
(e.g. SELECT sum(int2_col) FROM table where table has a single column),
it improves performance by about 20%. For more complex queries or tables
with wider rows, the relative performance improvement will not be as
significant.

src/backend/utils/adt/float.c
src/backend/utils/adt/numeric.c

index e51babf..c943ee2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.113 2005/02/11 04:08:58 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.114 2005/04/06 23:56:07 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1902,8 +1902,6 @@ float8_accum(PG_FUNCTION_ARGS)
        float8          N,
                                sumX,
                                sumX2;
-       Datum           transdatums[3];
-       ArrayType  *result;
 
        transvalues = check_float8_array(transarray, "float8_accum");
        N = transvalues[0];
@@ -1914,15 +1912,35 @@ float8_accum(PG_FUNCTION_ARGS)
        sumX += newval;
        sumX2 += newval * newval;
 
-       transdatums[0] = Float8GetDatumFast(N);
-       transdatums[1] = Float8GetDatumFast(sumX);
-       transdatums[2] = Float8GetDatumFast(sumX2);
+       /*
+        * If we're invoked by nodeAgg, we can cheat and modify our first
+        * parameter in-place to reduce palloc overhead. Otherwise we
+        * construct a new array with the updated transition data and
+        * return it.
+        */
+       if (fcinfo->context && IsA(fcinfo->context, AggState))
+       {
+               transvalues[0] = N;
+               transvalues[1] = sumX;
+               transvalues[2] = sumX2;
 
-       result = construct_array(transdatums, 3,
-                                                        FLOAT8OID,
-                                                sizeof(float8), false /* float8 byval */ , 'd');
+               PG_RETURN_ARRAYTYPE_P(transarray);
+       }
+       else
+       {
+               Datum           transdatums[3];
+               ArrayType  *result;
+
+               transdatums[0] = Float8GetDatumFast(N);
+               transdatums[1] = Float8GetDatumFast(sumX);
+               transdatums[2] = Float8GetDatumFast(sumX2);
 
-       PG_RETURN_ARRAYTYPE_P(result);
+               result = construct_array(transdatums, 3,
+                                                                FLOAT8OID,
+                                                                sizeof(float8), false /* float8 byval */ , 'd');
+
+               PG_RETURN_ARRAYTYPE_P(result);
+       }
 }
 
 Datum
@@ -1935,8 +1953,6 @@ float4_accum(PG_FUNCTION_ARGS)
                                sumX,
                                sumX2,
                                newval;
-       Datum           transdatums[3];
-       ArrayType  *result;
 
        transvalues = check_float8_array(transarray, "float4_accum");
        N = transvalues[0];
@@ -1950,15 +1966,35 @@ float4_accum(PG_FUNCTION_ARGS)
        sumX += newval;
        sumX2 += newval * newval;
 
-       transdatums[0] = Float8GetDatumFast(N);
-       transdatums[1] = Float8GetDatumFast(sumX);
-       transdatums[2] = Float8GetDatumFast(sumX2);
+       /*
+        * If we're invoked by nodeAgg, we can cheat and modify our first
+        * parameter in-place to reduce palloc overhead. Otherwise we
+        * construct a new array with the updated transition data and
+        * return it.
+        */
+       if (fcinfo->context && IsA(fcinfo->context, AggState))
+       {
+               transvalues[0] = N;
+               transvalues[1] = sumX;
+               transvalues[2] = sumX2;
 
-       result = construct_array(transdatums, 3,
-                                                        FLOAT8OID,
-                                                sizeof(float8), false /* float8 byval */ , 'd');
+               PG_RETURN_ARRAYTYPE_P(transarray);
+       }
+       else
+       {
+               Datum           transdatums[3];
+               ArrayType  *result;
+
+               transdatums[0] = Float8GetDatumFast(N);
+               transdatums[1] = Float8GetDatumFast(sumX);
+               transdatums[2] = Float8GetDatumFast(sumX2);
 
-       PG_RETURN_ARRAYTYPE_P(result);
+               result = construct_array(transdatums, 3,
+                                                                FLOAT8OID,
+                                                                sizeof(float8), false /* float8 byval */ , 'd');
+
+               PG_RETURN_ARRAYTYPE_P(result);
+       }
 }
 
 Datum
index a459ca2..214f9ff 100644 (file)
@@ -14,7 +14,7 @@
  * Copyright (c) 1998-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.82 2005/04/04 23:50:27 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.83 2005/04/06 23:56:07 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2357,7 +2357,6 @@ numeric_stddev(PG_FUNCTION_ARGS)
 Datum
 int2_sum(PG_FUNCTION_ARGS)
 {
-       int64           oldsum;
        int64           newval;
 
        if (PG_ARGISNULL(0))
@@ -2370,22 +2369,39 @@ int2_sum(PG_FUNCTION_ARGS)
                PG_RETURN_INT64(newval);
        }
 
-       oldsum = PG_GETARG_INT64(0);
+       /*
+        * If we're invoked by nodeAgg, we can cheat and modify out first
+        * parameter in-place to avoid palloc overhead. If not, we need to
+        * return the new value of the transition variable.
+        */
+       if (fcinfo->context && IsA(fcinfo->context, AggState))
+       {
+               int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
 
-       /* Leave sum unchanged if new input is null. */
-       if (PG_ARGISNULL(1))
-               PG_RETURN_INT64(oldsum);
+               /* Leave the running sum unchanged in the new input is null */
+               if (!PG_ARGISNULL(1))
+                       *oldsum = *oldsum + (int64) PG_GETARG_INT16(1);
 
-       /* OK to do the addition. */
-       newval = oldsum + (int64) PG_GETARG_INT16(1);
+               PG_RETURN_POINTER(oldsum);
+       }
+       else
+       {
+               int64           oldsum = PG_GETARG_INT64(0);
+
+               /* Leave sum unchanged if new input is null. */
+               if (PG_ARGISNULL(1))
+                       PG_RETURN_INT64(oldsum);
+
+               /* OK to do the addition. */
+               newval = oldsum + (int64) PG_GETARG_INT16(1);
 
-       PG_RETURN_INT64(newval);
+               PG_RETURN_INT64(newval);
+       }
 }
 
 Datum
 int4_sum(PG_FUNCTION_ARGS)
 {
-       int64           oldsum;
        int64           newval;
 
        if (PG_ARGISNULL(0))
@@ -2398,16 +2414,34 @@ int4_sum(PG_FUNCTION_ARGS)
                PG_RETURN_INT64(newval);
        }
 
-       oldsum = PG_GETARG_INT64(0);
+       /*
+        * If we're invoked by nodeAgg, we can cheat and modify out first
+        * parameter in-place to avoid palloc overhead. If not, we need to
+        * return the new value of the transition variable.
+        */
+       if (fcinfo->context && IsA(fcinfo->context, AggState))
+       {
+               int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
 
-       /* Leave sum unchanged if new input is null. */
-       if (PG_ARGISNULL(1))
-               PG_RETURN_INT64(oldsum);
+               /* Leave the running sum unchanged in the new input is null */
+               if (!PG_ARGISNULL(1))
+                       *oldsum = *oldsum + (int64) PG_GETARG_INT32(1);
 
-       /* OK to do the addition. */
-       newval = oldsum + (int64) PG_GETARG_INT32(1);
+               PG_RETURN_POINTER(oldsum);
+       }
+       else
+       {
+               int64           oldsum = PG_GETARG_INT64(0);
 
-       PG_RETURN_INT64(newval);
+               /* Leave sum unchanged if new input is null. */
+               if (PG_ARGISNULL(1))
+                       PG_RETURN_INT64(oldsum);
+
+               /* OK to do the addition. */
+               newval = oldsum + (int64) PG_GETARG_INT32(1);
+
+               PG_RETURN_INT64(newval);
+       }
 }
 
 Datum
@@ -2426,6 +2460,12 @@ int8_sum(PG_FUNCTION_ARGS)
                PG_RETURN_DATUM(newval);
        }
 
+       /*
+        * Note that we cannot special-case the nodeAgg case here, as we
+        * do for int2_sum and int4_sum: numeric is of variable size, so
+        * we cannot modify our first parameter in-place.
+        */
+
        oldsum = PG_GETARG_NUMERIC(0);
 
        /* Leave sum unchanged if new input is null. */