Skip to content

Commit be2f825

Browse files
author
Neil Conway
committed
Apply the "nodeAgg" optimization to more of the builtin transition
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.
1 parent a6bbfed commit be2f825

File tree

2 files changed

+112
-36
lines changed

2 files changed

+112
-36
lines changed

src/backend/utils/adt/float.c

+55-19
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.113 2005/02/11 04:08:58 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.114 2005/04/06 23:56:07 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1902,8 +1902,6 @@ float8_accum(PG_FUNCTION_ARGS)
19021902
float8 N,
19031903
sumX,
19041904
sumX2;
1905-
Datum transdatums[3];
1906-
ArrayType *result;
19071905

19081906
transvalues = check_float8_array(transarray, "float8_accum");
19091907
N = transvalues[0];
@@ -1914,15 +1912,35 @@ float8_accum(PG_FUNCTION_ARGS)
19141912
sumX += newval;
19151913
sumX2 += newval * newval;
19161914

1917-
transdatums[0] = Float8GetDatumFast(N);
1918-
transdatums[1] = Float8GetDatumFast(sumX);
1919-
transdatums[2] = Float8GetDatumFast(sumX2);
1915+
/*
1916+
* If we're invoked by nodeAgg, we can cheat and modify our first
1917+
* parameter in-place to reduce palloc overhead. Otherwise we
1918+
* construct a new array with the updated transition data and
1919+
* return it.
1920+
*/
1921+
if (fcinfo->context && IsA(fcinfo->context, AggState))
1922+
{
1923+
transvalues[0] = N;
1924+
transvalues[1] = sumX;
1925+
transvalues[2] = sumX2;
19201926

1921-
result = construct_array(transdatums, 3,
1922-
FLOAT8OID,
1923-
sizeof(float8), false /* float8 byval */ , 'd');
1927+
PG_RETURN_ARRAYTYPE_P(transarray);
1928+
}
1929+
else
1930+
{
1931+
Datum transdatums[3];
1932+
ArrayType *result;
1933+
1934+
transdatums[0] = Float8GetDatumFast(N);
1935+
transdatums[1] = Float8GetDatumFast(sumX);
1936+
transdatums[2] = Float8GetDatumFast(sumX2);
19241937

1925-
PG_RETURN_ARRAYTYPE_P(result);
1938+
result = construct_array(transdatums, 3,
1939+
FLOAT8OID,
1940+
sizeof(float8), false /* float8 byval */ , 'd');
1941+
1942+
PG_RETURN_ARRAYTYPE_P(result);
1943+
}
19261944
}
19271945

19281946
Datum
@@ -1935,8 +1953,6 @@ float4_accum(PG_FUNCTION_ARGS)
19351953
sumX,
19361954
sumX2,
19371955
newval;
1938-
Datum transdatums[3];
1939-
ArrayType *result;
19401956

19411957
transvalues = check_float8_array(transarray, "float4_accum");
19421958
N = transvalues[0];
@@ -1950,15 +1966,35 @@ float4_accum(PG_FUNCTION_ARGS)
19501966
sumX += newval;
19511967
sumX2 += newval * newval;
19521968

1953-
transdatums[0] = Float8GetDatumFast(N);
1954-
transdatums[1] = Float8GetDatumFast(sumX);
1955-
transdatums[2] = Float8GetDatumFast(sumX2);
1969+
/*
1970+
* If we're invoked by nodeAgg, we can cheat and modify our first
1971+
* parameter in-place to reduce palloc overhead. Otherwise we
1972+
* construct a new array with the updated transition data and
1973+
* return it.
1974+
*/
1975+
if (fcinfo->context && IsA(fcinfo->context, AggState))
1976+
{
1977+
transvalues[0] = N;
1978+
transvalues[1] = sumX;
1979+
transvalues[2] = sumX2;
19561980

1957-
result = construct_array(transdatums, 3,
1958-
FLOAT8OID,
1959-
sizeof(float8), false /* float8 byval */ , 'd');
1981+
PG_RETURN_ARRAYTYPE_P(transarray);
1982+
}
1983+
else
1984+
{
1985+
Datum transdatums[3];
1986+
ArrayType *result;
1987+
1988+
transdatums[0] = Float8GetDatumFast(N);
1989+
transdatums[1] = Float8GetDatumFast(sumX);
1990+
transdatums[2] = Float8GetDatumFast(sumX2);
19601991

1961-
PG_RETURN_ARRAYTYPE_P(result);
1992+
result = construct_array(transdatums, 3,
1993+
FLOAT8OID,
1994+
sizeof(float8), false /* float8 byval */ , 'd');
1995+
1996+
PG_RETURN_ARRAYTYPE_P(result);
1997+
}
19621998
}
19631999

19642000
Datum

src/backend/utils/adt/numeric.c

+57-17
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* Copyright (c) 1998-2005, PostgreSQL Global Development Group
1515
*
1616
* IDENTIFICATION
17-
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.82 2005/04/04 23:50:27 neilc Exp $
17+
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.83 2005/04/06 23:56:07 neilc Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -2357,7 +2357,6 @@ numeric_stddev(PG_FUNCTION_ARGS)
23572357
Datum
23582358
int2_sum(PG_FUNCTION_ARGS)
23592359
{
2360-
int64 oldsum;
23612360
int64 newval;
23622361

23632362
if (PG_ARGISNULL(0))
@@ -2370,22 +2369,39 @@ int2_sum(PG_FUNCTION_ARGS)
23702369
PG_RETURN_INT64(newval);
23712370
}
23722371

2373-
oldsum = PG_GETARG_INT64(0);
2372+
/*
2373+
* If we're invoked by nodeAgg, we can cheat and modify out first
2374+
* parameter in-place to avoid palloc overhead. If not, we need to
2375+
* return the new value of the transition variable.
2376+
*/
2377+
if (fcinfo->context && IsA(fcinfo->context, AggState))
2378+
{
2379+
int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
23742380

2375-
/* Leave sum unchanged if new input is null. */
2376-
if (PG_ARGISNULL(1))
2377-
PG_RETURN_INT64(oldsum);
2381+
/* Leave the running sum unchanged in the new input is null */
2382+
if (!PG_ARGISNULL(1))
2383+
*oldsum = *oldsum + (int64) PG_GETARG_INT16(1);
23782384

2379-
/* OK to do the addition. */
2380-
newval = oldsum + (int64) PG_GETARG_INT16(1);
2385+
PG_RETURN_POINTER(oldsum);
2386+
}
2387+
else
2388+
{
2389+
int64 oldsum = PG_GETARG_INT64(0);
2390+
2391+
/* Leave sum unchanged if new input is null. */
2392+
if (PG_ARGISNULL(1))
2393+
PG_RETURN_INT64(oldsum);
2394+
2395+
/* OK to do the addition. */
2396+
newval = oldsum + (int64) PG_GETARG_INT16(1);
23812397

2382-
PG_RETURN_INT64(newval);
2398+
PG_RETURN_INT64(newval);
2399+
}
23832400
}
23842401

23852402
Datum
23862403
int4_sum(PG_FUNCTION_ARGS)
23872404
{
2388-
int64 oldsum;
23892405
int64 newval;
23902406

23912407
if (PG_ARGISNULL(0))
@@ -2398,16 +2414,34 @@ int4_sum(PG_FUNCTION_ARGS)
23982414
PG_RETURN_INT64(newval);
23992415
}
24002416

2401-
oldsum = PG_GETARG_INT64(0);
2417+
/*
2418+
* If we're invoked by nodeAgg, we can cheat and modify out first
2419+
* parameter in-place to avoid palloc overhead. If not, we need to
2420+
* return the new value of the transition variable.
2421+
*/
2422+
if (fcinfo->context && IsA(fcinfo->context, AggState))
2423+
{
2424+
int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
24022425

2403-
/* Leave sum unchanged if new input is null. */
2404-
if (PG_ARGISNULL(1))
2405-
PG_RETURN_INT64(oldsum);
2426+
/* Leave the running sum unchanged in the new input is null */
2427+
if (!PG_ARGISNULL(1))
2428+
*oldsum = *oldsum + (int64) PG_GETARG_INT32(1);
24062429

2407-
/* OK to do the addition. */
2408-
newval = oldsum + (int64) PG_GETARG_INT32(1);
2430+
PG_RETURN_POINTER(oldsum);
2431+
}
2432+
else
2433+
{
2434+
int64 oldsum = PG_GETARG_INT64(0);
24092435

2410-
PG_RETURN_INT64(newval);
2436+
/* Leave sum unchanged if new input is null. */
2437+
if (PG_ARGISNULL(1))
2438+
PG_RETURN_INT64(oldsum);
2439+
2440+
/* OK to do the addition. */
2441+
newval = oldsum + (int64) PG_GETARG_INT32(1);
2442+
2443+
PG_RETURN_INT64(newval);
2444+
}
24112445
}
24122446

24132447
Datum
@@ -2426,6 +2460,12 @@ int8_sum(PG_FUNCTION_ARGS)
24262460
PG_RETURN_DATUM(newval);
24272461
}
24282462

2463+
/*
2464+
* Note that we cannot special-case the nodeAgg case here, as we
2465+
* do for int2_sum and int4_sum: numeric is of variable size, so
2466+
* we cannot modify our first parameter in-place.
2467+
*/
2468+
24292469
oldsum = PG_GETARG_NUMERIC(0);
24302470

24312471
/* Leave sum unchanged if new input is null. */

0 commit comments

Comments
 (0)