Neil Conway wrote:
Yeah, there might be some others we could improve. float4_accum() and
float8_accum() look like they could be improved pretty easily, and
do_numeric_accum() should also be fixable with some hackery. I suppose
it's also worth optimizing int2_sum(), int4_sum() and int8_sum().
Attached is a patch that applies the same optimization to int2_sum(),
int4_sum(), float4_accum(), and float8_accum(). It wasn't possible to
optimize do_numeric_accum() or int8_sum() since they both use numerics.
Performance gains are similar to those measured when this optimization
has been applied to similar aggregates (e.g. avg(float8) goes from about
6400 ms to about 4300 ms on my machine, for a single column of float8
and about 1 million rows).
Barring any objections, I'll apply this to HEAD tomorrow.
-Neil
Index: src/backend/utils/adt/float.c
===
RCS file: /Users/neilc/local/cvs/pgsql/src/backend/utils/adt/float.c,v
retrieving revision 1.113
diff -c -r1.113 float.c
*** src/backend/utils/adt/float.c 11 Feb 2005 04:08:58 - 1.113
--- src/backend/utils/adt/float.c 6 Apr 2005 07:24:38 -
***
*** 1902,1909
float8 N,
sumX,
sumX2;
- Datum transdatums[3];
- ArrayType *result;
transvalues = check_float8_array(transarray, "float8_accum");
N = transvalues[0];
--- 1902,1907
***
*** 1914,1928
sumX += newval;
sumX2 += newval * newval;
! transdatums[0] = Float8GetDatumFast(N);
! transdatums[1] = Float8GetDatumFast(sumX);
! transdatums[2] = Float8GetDatumFast(sumX2);
!
! result = construct_array(transdatums, 3,
! FLOAT8OID,
! sizeof(float8), false /* float8 byval */ , 'd');
! PG_RETURN_ARRAYTYPE_P(result);
}
Datum
--- 1912,1946
sumX += newval;
sumX2 += newval * newval;
! /*
! * 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;
!
! PG_RETURN_ARRAYTYPE_P(transarray);
! }
! else
! {
! Datum transdatums[3];
! ArrayType *result;
!
! transdatums[0] = Float8GetDatumFast(N);
! transdatums[1] = Float8GetDatumFast(sumX);
! transdatums[2] = Float8GetDatumFast(sumX2);
!
! result = construct_array(transdatums, 3,
! FLOAT8OID,
! sizeof(float8), false /* float8 byval */ , 'd');
! PG_RETURN_ARRAYTYPE_P(result);
! }
}
Datum
***
*** 1935,1942
sumX,
sumX2,
newval;
- Datum transdatums[3];
- ArrayType *result;
transvalues = check_float8_array(transarray, "float4_accum");
N = transvalues[0];
--- 1953,1958
***
*** 1950,1964
sumX += newval;
sumX2 += newval * newval;
! transdatums[0] = Float8GetDatumFast(N);
! transdatums[1] = Float8GetDatumFast(sumX);
! transdatums[2] = Float8GetDatumFast(sumX2);
!
! result = construct_array(transdatums, 3,
! FLOAT8OID,
! sizeof(float8), false /* float8 byval */ , 'd');
! PG_RETURN_ARRAYTYPE_P(result);
}
Datum
--- 1966,2000
sumX += newval;
sumX2 += newval * newval;
! /*
! * 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;
!
! PG_RETURN_ARRAYTYPE_P(transarray);
! }
! else
! {
! Datum transdatums[3];
! ArrayType *result;
!
! transdatums[0] = Float8GetDatumFast(N);
! transdatums[1] = Float8GetDatumFast(sumX);
! transdatums[2] = Float8GetDatumFast(sumX2);
!
! result = construct_array(transdatums, 3,
! FLOAT8OID,
! sizeof(float8), false /* float8 byval */ , 'd');
! PG_RETURN_ARRAYTYPE_P(result);
! }
}
Datum
Index: src/backend/utils/adt/numeric.c
===
RCS file: /Users/neilc/local/cvs/pgsql/src/backend/utils/adt/numeric.c,v
retrieving revision 1.82
diff -c -r1.82 numeric.c
*** src/backend/utils/adt/numeric.c 4 Apr 2005 23:50:27 - 1.82
--- src/backend/utils/adt/numeric.c 6 Apr 2005 08:07:37 -
***
*** 2357,2363
Datum
int2_sum(PG_FUNCTION_ARGS)
{
- int64 oldsum;
int64 newval;
if (PG_ARGISNULL(0))
--- 2357,2362
***
*** 2370,2391
PG_RETURN_INT64(newval);
}
! 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_G