mirror of
https://github.com/postgres/postgres.git
synced 2025-10-16 17:07:43 +03:00
Allow negative aggtransspace to indicate unbounded state size
This patch reuses the existing aggtransspace in pg_aggregate to signal that an aggregate's transition state can grow unboundedly. If aggtransspace is set to a negative value, it now indicates that the transition state may consume unpredictable or large amounts of memory, such as in aggregates like array_agg or string_agg that accumulate input rows. This information can be used by the planner to avoid applying memory-sensitive optimizations (e.g., eager aggregation) when there is a risk of excessive memory usage during partial aggregation. Bump catalog version. Per idea from Robert Haas, though applied differently than originally suggested. Discussion: https://postgr.es/m/CA+TgmoYbkvYwLa+1vOP7RDY7kO2=A7rppoPusoRXe44VDOGBPg@mail.gmail.com
This commit is contained in:
@@ -596,7 +596,10 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Approximate average size (in bytes) of the transition state
|
Approximate average size (in bytes) of the transition state
|
||||||
data, or zero to use a default estimate
|
data. A positive value provides an estimate; zero means to
|
||||||
|
use a default estimate. A negative value indicates the state
|
||||||
|
data can grow unboundedly in size, such as when the aggregate
|
||||||
|
accumulates input rows (e.g., array_agg, string_agg).
|
||||||
</para></entry>
|
</para></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
@@ -384,9 +384,13 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
|
|||||||
<para>
|
<para>
|
||||||
The approximate average size (in bytes) of the aggregate's state value.
|
The approximate average size (in bytes) of the aggregate's state value.
|
||||||
If this parameter is omitted or is zero, a default estimate is used
|
If this parameter is omitted or is zero, a default estimate is used
|
||||||
based on the <replaceable>state_data_type</replaceable>.
|
based on the <replaceable>state_data_type</replaceable>. If set to a
|
||||||
|
negative value, it indicates the state data can grow unboundedly in
|
||||||
|
size, such as when the aggregate accumulates input rows (e.g.,
|
||||||
|
array_agg, string_agg).
|
||||||
The planner uses this value to estimate the memory required for a
|
The planner uses this value to estimate the memory required for a
|
||||||
grouped aggregate query.
|
grouped aggregate query and to avoid optimizations that may cause
|
||||||
|
excessive memory usage.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@@ -568,7 +572,8 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
|
|||||||
<para>
|
<para>
|
||||||
The approximate average size (in bytes) of the aggregate's state
|
The approximate average size (in bytes) of the aggregate's state
|
||||||
value, when using moving-aggregate mode. This works the same as
|
value, when using moving-aggregate mode. This works the same as
|
||||||
<replaceable>state_data_size</replaceable>.
|
<replaceable>state_data_size</replaceable>, except that negative
|
||||||
|
values are not used to indicate unbounded state size.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@@ -57,6 +57,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 202510081
|
#define CATALOG_VERSION_NO 202510082
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -558,26 +558,28 @@
|
|||||||
aggfinalfn => 'array_agg_finalfn', aggcombinefn => 'array_agg_combine',
|
aggfinalfn => 'array_agg_finalfn', aggcombinefn => 'array_agg_combine',
|
||||||
aggserialfn => 'array_agg_serialize',
|
aggserialfn => 'array_agg_serialize',
|
||||||
aggdeserialfn => 'array_agg_deserialize', aggfinalextra => 't',
|
aggdeserialfn => 'array_agg_deserialize', aggfinalextra => 't',
|
||||||
aggtranstype => 'internal' },
|
aggtranstype => 'internal', aggtransspace => '-1' },
|
||||||
{ aggfnoid => 'array_agg(anyarray)', aggtransfn => 'array_agg_array_transfn',
|
{ aggfnoid => 'array_agg(anyarray)', aggtransfn => 'array_agg_array_transfn',
|
||||||
aggfinalfn => 'array_agg_array_finalfn',
|
aggfinalfn => 'array_agg_array_finalfn',
|
||||||
aggcombinefn => 'array_agg_array_combine',
|
aggcombinefn => 'array_agg_array_combine',
|
||||||
aggserialfn => 'array_agg_array_serialize',
|
aggserialfn => 'array_agg_array_serialize',
|
||||||
aggdeserialfn => 'array_agg_array_deserialize', aggfinalextra => 't',
|
aggdeserialfn => 'array_agg_array_deserialize', aggfinalextra => 't',
|
||||||
aggtranstype => 'internal' },
|
aggtranstype => 'internal', aggtransspace => '-1' },
|
||||||
|
|
||||||
# text
|
# text
|
||||||
{ aggfnoid => 'string_agg(text,text)', aggtransfn => 'string_agg_transfn',
|
{ aggfnoid => 'string_agg(text,text)', aggtransfn => 'string_agg_transfn',
|
||||||
aggfinalfn => 'string_agg_finalfn', aggcombinefn => 'string_agg_combine',
|
aggfinalfn => 'string_agg_finalfn', aggcombinefn => 'string_agg_combine',
|
||||||
aggserialfn => 'string_agg_serialize',
|
aggserialfn => 'string_agg_serialize',
|
||||||
aggdeserialfn => 'string_agg_deserialize', aggtranstype => 'internal' },
|
aggdeserialfn => 'string_agg_deserialize',
|
||||||
|
aggtranstype => 'internal', aggtransspace => '-1' },
|
||||||
|
|
||||||
# bytea
|
# bytea
|
||||||
{ aggfnoid => 'string_agg(bytea,bytea)',
|
{ aggfnoid => 'string_agg(bytea,bytea)',
|
||||||
aggtransfn => 'bytea_string_agg_transfn',
|
aggtransfn => 'bytea_string_agg_transfn',
|
||||||
aggfinalfn => 'bytea_string_agg_finalfn',
|
aggfinalfn => 'bytea_string_agg_finalfn',
|
||||||
aggcombinefn => 'string_agg_combine', aggserialfn => 'string_agg_serialize',
|
aggcombinefn => 'string_agg_combine', aggserialfn => 'string_agg_serialize',
|
||||||
aggdeserialfn => 'string_agg_deserialize', aggtranstype => 'internal' },
|
aggdeserialfn => 'string_agg_deserialize',
|
||||||
|
aggtranstype => 'internal', aggtransspace => '-1' },
|
||||||
|
|
||||||
# range
|
# range
|
||||||
{ aggfnoid => 'range_intersect_agg(anyrange)',
|
{ aggfnoid => 'range_intersect_agg(anyrange)',
|
||||||
|
@@ -1470,7 +1470,7 @@ WHERE aggfnoid = 0 OR aggtransfn = 0 OR
|
|||||||
(aggkind = 'n' AND aggnumdirectargs > 0) OR
|
(aggkind = 'n' AND aggnumdirectargs > 0) OR
|
||||||
aggfinalmodify NOT IN ('r', 's', 'w') OR
|
aggfinalmodify NOT IN ('r', 's', 'w') OR
|
||||||
aggmfinalmodify NOT IN ('r', 's', 'w') OR
|
aggmfinalmodify NOT IN ('r', 's', 'w') OR
|
||||||
aggtranstype = 0 OR aggtransspace < 0 OR aggmtransspace < 0;
|
aggtranstype = 0 OR aggmtransspace < 0;
|
||||||
ctid | aggfnoid
|
ctid | aggfnoid
|
||||||
------+----------
|
------+----------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
@@ -847,7 +847,7 @@ WHERE aggfnoid = 0 OR aggtransfn = 0 OR
|
|||||||
(aggkind = 'n' AND aggnumdirectargs > 0) OR
|
(aggkind = 'n' AND aggnumdirectargs > 0) OR
|
||||||
aggfinalmodify NOT IN ('r', 's', 'w') OR
|
aggfinalmodify NOT IN ('r', 's', 'w') OR
|
||||||
aggmfinalmodify NOT IN ('r', 's', 'w') OR
|
aggmfinalmodify NOT IN ('r', 's', 'w') OR
|
||||||
aggtranstype = 0 OR aggtransspace < 0 OR aggmtransspace < 0;
|
aggtranstype = 0 OR aggmtransspace < 0;
|
||||||
|
|
||||||
-- Make sure the matching pg_proc entry is sensible, too.
|
-- Make sure the matching pg_proc entry is sensible, too.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user