1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-27 23:21:58 +03:00

Create AVG() aggregates for int8 and NUMERIC which do not compute X^2,

as a performance enhancement.

Mark Kirkwood
This commit is contained in:
Bruce Momjian
2007-02-17 00:55:58 +00:00
parent 72a070a365
commit 89a624439e
7 changed files with 84 additions and 17 deletions

View File

@ -14,7 +14,7 @@
* Copyright (c) 1998-2007, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.99 2007/01/16 21:41:13 neilc Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.100 2007/02/17 00:55:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -2165,6 +2165,40 @@ do_numeric_accum(ArrayType *transarray, Numeric newval)
return result;
}
/*
* Improve avg performance by not caclulating sum(X*X).
*/
static ArrayType *
do_numeric_avg_accum(ArrayType *transarray, Numeric newval)
{
Datum *transdatums;
int ndatums;
Datum N,
sumX;
ArrayType *result;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
NUMERICOID, -1, false, 'i',
&transdatums, NULL, &ndatums);
if (ndatums != 2)
elog(ERROR, "expected 2-element numeric array");
N = transdatums[0];
sumX = transdatums[1];
N = DirectFunctionCall1(numeric_inc, N);
sumX = DirectFunctionCall2(numeric_add, sumX,
NumericGetDatum(newval));
transdatums[0] = N;
transdatums[1] = sumX;
result = construct_array(transdatums, 2,
NUMERICOID, -1, false, 'i');
return result;
}
Datum
numeric_accum(PG_FUNCTION_ARGS)
{
@ -2174,6 +2208,18 @@ numeric_accum(PG_FUNCTION_ARGS)
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
/*
* Optimized case for average of numeric.
*/
Datum
numeric_avg_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Numeric newval = PG_GETARG_NUMERIC(1);
PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
}
/*
* Integer data types all use Numeric accumulators to share code and
* avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
@ -2219,6 +2265,22 @@ int8_accum(PG_FUNCTION_ARGS)
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
/*
* Optimized case for average of int8.
*/
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum newval8 = PG_GETARG_DATUM(1);
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
}
Datum
numeric_avg(PG_FUNCTION_ARGS)
{
@ -2232,11 +2294,10 @@ numeric_avg(PG_FUNCTION_ARGS)
deconstruct_array(transarray,
NUMERICOID, -1, false, 'i',
&transdatums, NULL, &ndatums);
if (ndatums != 3)
elog(ERROR, "expected 3-element numeric array");
if (ndatums != 2)
elog(ERROR, "expected 2-element numeric array");
N = DatumGetNumeric(transdatums[0]);
sumX = DatumGetNumeric(transdatums[1]);
/* ignore sumX2 */
/* SQL92 defines AVG of no values to be NULL */
/* N is zero iff no digits (cf. numeric_uminus) */