OSDN Git Service

Create AVG() aggregates for int8 and NUMERIC which do not compute X^2,
authorBruce Momjian <bruce@momjian.us>
Sat, 17 Feb 2007 00:55:58 +0000 (00:55 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 17 Feb 2007 00:55:58 +0000 (00:55 +0000)
as a performance enhancement.

Mark Kirkwood

src/backend/utils/adt/numeric.c
src/include/catalog/catversion.h
src/include/catalog/pg_aggregate.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/test/regress/expected/create_aggregate.out
src/test/regress/sql/create_aggregate.sql

index 7e51873..19fc4d4 100644 (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)
 {
@@ -2175,6 +2209,18 @@ numeric_accum(PG_FUNCTION_ARGS)
 }
 
 /*
+ * 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
  * is overkill for the N and sum(X) values, but definitely not overkill
@@ -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) */
index 88e4459..5402186 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.385 2007/02/16 07:46:55 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.386 2007/02/17 00:55:57 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200702161
+#define CATALOG_VERSION_NO     200702162
 
 #endif
index 1f2ba57..9036b1d 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_aggregate.h,v 1.60 2007/01/20 09:27:19 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_aggregate.h,v 1.61 2007/02/17 00:55:57 momjian Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -80,10 +80,10 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
  */
 
 /* avg */
-DATA(insert ( 2100     int8_accum              numeric_avg             0       1231    "{0,0,0}" ));
+DATA(insert ( 2100     int8_avg_accum  numeric_avg             0       1231    "{0,0}" ));
 DATA(insert ( 2101     int4_avg_accum  int8_avg                0       1016    "{0,0}" ));
 DATA(insert ( 2102     int2_avg_accum  int8_avg                0       1016    "{0,0}" ));
-DATA(insert ( 2103     numeric_accum   numeric_avg             0       1231    "{0,0,0}" ));
+DATA(insert ( 2103     numeric_avg_accum       numeric_avg             0       1231    "{0,0}" ));
 DATA(insert ( 2104     float4_accum    float8_avg              0       1022    "{0,0,0}" ));
 DATA(insert ( 2105     float8_accum    float8_avg              0       1022    "{0,0,0}" ));
 DATA(insert ( 2106     interval_accum  interval_avg    0       1187    "{0 second,0 second}" ));
index a8fc694..6a93090 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.444 2007/02/16 07:46:55 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.445 2007/02/17 00:55:57 momjian Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -2744,12 +2744,16 @@ DATA(insert OID = 1832 (  float8_stddev_samp    PGNSP PGUID 12 1 0 f f t f i 1 701
 DESCR("STDDEV_SAMP aggregate final function");
 DATA(insert OID = 1833 (  numeric_accum    PGNSP PGUID 12 1 0 f f t f i 2 1231 "1231 1700" _null_ _null_ _null_ numeric_accum - _null_ ));
 DESCR("aggregate transition function");
+DATA(insert OID = 2858 (  numeric_avg_accum    PGNSP PGUID 12 1 0 f f t f i 2 1231 "1231 1700" _null_ _null_ _null_ numeric_avg_accum - _null_ ));
+DESCR("aggregate transition function");
 DATA(insert OID = 1834 (  int2_accum      PGNSP PGUID 12 1 0 f f t f i 2 1231 "1231 21" _null_ _null_ _null_ int2_accum - _null_ ));
 DESCR("aggregate transition function");
 DATA(insert OID = 1835 (  int4_accum      PGNSP PGUID 12 1 0 f f t f i 2 1231 "1231 23" _null_ _null_ _null_ int4_accum - _null_ ));
 DESCR("aggregate transition function");
 DATA(insert OID = 1836 (  int8_accum      PGNSP PGUID 12 1 0 f f t f i 2 1231 "1231 20" _null_ _null_ _null_ int8_accum - _null_ ));
 DESCR("aggregate transition function");
+DATA(insert OID = 2746 (  int8_avg_accum          PGNSP PGUID 12 1 0 f f t f i 2 1231 "1231 20" _null_ _null_ _null_ int8_avg_accum - _null_ ));
+DESCR("aggregate transition function");
 DATA(insert OID = 1837 (  numeric_avg     PGNSP PGUID 12 1 0 f f t f i 1 1700 "1231" _null_ _null_ _null_      numeric_avg - _null_ ));
 DESCR("AVG aggregate final function");
 DATA(insert OID = 2514 (  numeric_var_pop  PGNSP PGUID 12 1 0 f f t f i 1 1700 "1231" _null_ _null_ _null_     numeric_var_pop - _null_ ));
index aee4095..db4357c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.287 2007/01/28 16:16:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.288 2007/02/17 00:55:58 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -841,9 +841,11 @@ extern Datum numeric_float4(PG_FUNCTION_ARGS);
 extern Datum text_numeric(PG_FUNCTION_ARGS);
 extern Datum numeric_text(PG_FUNCTION_ARGS);
 extern Datum numeric_accum(PG_FUNCTION_ARGS);
+extern Datum numeric_avg_accum(PG_FUNCTION_ARGS);
 extern Datum int2_accum(PG_FUNCTION_ARGS);
 extern Datum int4_accum(PG_FUNCTION_ARGS);
 extern Datum int8_accum(PG_FUNCTION_ARGS);
+extern Datum int8_avg_accum(PG_FUNCTION_ARGS);
 extern Datum numeric_avg(PG_FUNCTION_ARGS);
 extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
 extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
index 08daaa8..1c540b2 100644 (file)
@@ -3,9 +3,9 @@
 --
 -- all functions CREATEd
 CREATE AGGREGATE newavg (
-   sfunc = int4_accum, basetype = int4, stype = _numeric
-   finalfunc = numeric_avg,
-   initcond1 = '{0,0,0}'
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
 );
 -- test comments
 COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
index 891b0e0..9d02048 100644 (file)
@@ -4,9 +4,9 @@
 
 -- all functions CREATEd
 CREATE AGGREGATE newavg (
-   sfunc = int4_accum, basetype = int4, stype = _numeric
-   finalfunc = numeric_avg,
-   initcond1 = '{0,0,0}'
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
 );
 
 -- test comments