CREATE AGGREGATE
CREATE AGGREGATE¶
定义新的聚集函数
- 语法
-
``` sql CREATE AGGREGATE name ( [ argmode ] [ ] arg_data_type [ , … ] ) ( SFUNC = sfunc, STYPE = state_data_type [ , SSPACE = state_data_size ] [ , FINALFUNC = ffunc ] [ , FINALFUNC_EXTRA ] [ , COMBINEFUNC = combinefunc ] [ , SERIALFUNC = serialfunc ] [ , DESERIALFUNC = deserialfunc ] [ , INITCOND = initial_condition ] [ , MSFUNC = msfunc ] [ , MINVFUNC = minvfunc ] [ , MSTYPE = mstate_data_type ] [ , MSSPACE = mstate_data_size ] [ , MFINALFUNC = mffunc ] [ , MFINALFUNC_EXTRA ] [ , MINITCOND = minitial_condition ] [ , SORTOP = sort_operator ] )
CREATE AGGREGATE name ( [ [ argmode ] [ argname ] arg_data_type [ , … ] ] ORDER BY [ argmode ] [ argname ] arg_data_type [ , … ] ) ( SFUNC = sfunc, STYPE = state_data_type [ , SSPACE = state_data_size ] [ , FINALFUNC = ffunc ] [ , FINALFUNC_EXTRA ] [ , COMBINEFUNC = combinefunc ] [ , SERIALFUNC = serialfunc ] [ , DESERIALFUNC = deserialfunc ] [ , INITCOND = initial_condition ] [ , HYPOTHETICAL ] )
```
- 描述
-
CREATE AGGREGATE
定义一个新的聚合函数。 SeaboxMPP数据库中已经提供了一些基本且常用的聚合函数,例如count
,min
,max
,sum
,avg
等。如果定义了新类型或需要尚未提供的聚合函数,则可以使用
CREATE AGGREGATE
提供所需的功能。如果指定了模式名称(例如
CREATE AGGREGATE myschema.myagg ...
),则将在指定的模式中创建聚合函数。否则,它将在当前模式中创建。聚合函数由其名称和输入数据类型标识。 如果同一模式中的两个聚合函数对不同的输入类型进行操作,则它们可以具有相同的名称。
聚合函数的名称和输入数据类型也必须与同一模式中每个普通函数的名称和输入数据类型不同。此行为与普通函数名称的重载相同。 请参阅
CREATE FUNCTION
。一个简单的聚合函数由一个,两个或三个普通函数(必须是
IMMUTABLE
函数)组成:状态转换函数
sfunc
可选的最终计算函数
ffunc
可选的合并函数
combinefunc
这些函数的用法如下:
sfunc( internal-state, next-data-values ) ---> next-internal-state ffunc( internal-state ) ---> aggregate-value combinefunc( internal-state, internal-state ) ---> next-internal-state
数据库创建一个数据类型为
stype
的临时变量,以保存聚合函数的当前内部状态。在每个输入行,将计算聚合参数值,并使用当前状态值和新参数值调用状态转换函数以计算新的内部状态值。处理完所有行后,将一次调用最终函数以计算合计返回值。 如果没有最终函数,则按原样返回最终状态值。可以将
combinefunc
指定为优化聚合执行的方法。通过指定combinefunc
,可以首先在Executor上并行执行聚合,然后在Coordinator实例上并行执行。当执行两级执行时,在Executor上执行sfunc
以生成部分聚合结果,而在Coordinator实例上执行combinefunc
来聚合Executor中的部分结果。如果执行单级聚合,则将所有行发送到Coordinator实例,并将sfunc
应用于行。单级聚合和二级聚合是等效的执行策略。 两种类型的聚合都可以在查询计划中实现。在实现函数
combinefunc
和sfunc
时,必须确保在Executor实例上调用sfunc
,然后在Coordinator实例上调用combinefunc
产生与将所有行发送到Coordinator实例然后仅应用sfunc
到行的单级聚合相同的结果。聚合函数可以提供可选的初始条件,即内部状态值的初始值。它是作为text类型的值指定并存储在数据库中的,但是它必须是状态值数据类型的常量的有效外部表示形式。如果未提供,则状态值开始为
NULL
。如果状态转换函数声明为
STRICT
,则不能使用NULL
输入调用它。 使用这种转换函数,聚合执行的行为如下。输入值为空的行将被忽略(不调用该函数,并且保留先前的状态值)。如果初始状态值为NULL
,则在具有所有非空输入值的第一行,第一个参数值将替换状态值,并且在具有所有非空输入值的后续行中调用转换函数。这对于实现像max
这样的聚合很有用。请注意,只有当state_data_type
与第一个input_data_type
相同时,此行为才可用。当这些类型不同时,必须提供一个非空的初始条件或使用一个非严格的转换函数。如果未将状态转换函数声明为
STRICT
,则将在每个输入行无条件调用该状态转换函数, 并且必须自己处理NULL
输入和NULL
转换值。这使聚合作者可以完全控制聚合对NULL
值的处理。如果将最终函数声明为
STRICT
,则当结束状态值为NULL
时将不调用该函数;而是将自动返回NULL
结果(这是STRICT
函数的正常行为)。在任何情况下,最终函数都可以选择返回NULL
值。例如,当avg
的最终函数看到零个输入行时返回NULL
。有时,将最终函数声明为不仅接受状态值,而且接受与聚合的输入值相对应的额外参数是有用的。这样做的主要原因是,如果最终函数是多态的,那么状态值的数据类型将不足以用来确定结果类型。这些额外的参数始终以
NULL
的形式传递(因此,在使用FINALFUNC_EXTRA
选项时,最后的函数一定不能严格),但是它们仍然是有效的参数。例如,最终函数可以使用get_fn_expr_argtype
来标识当前调用中的实际参数类型。聚合可以选择支持移动聚合模式。需要指定
msfunc
,minfunc
和mstype
函数, 以及可选的mspace
,mfinalfunc
,mfinalfunc_extra
和minitcond
参数。除了minvfunc
以外,这些函数的工作与不带m
的相应简单聚合函数相似,它们定义了包含逆转换函数的聚合的单独实现。参数列表中带有
ORDER BY
的语法会创建一种特殊的聚合类型,称为有序集聚合。或者,如果指定了HYPOTHETICAL
,则创建一个假设集合。这些聚合以顺序相关的方式对排序值的组进行操作,因此指定输入排序顺序是调用的重要组成部分。而且,它们可以具有直接参数,这些参数是每个聚合仅评估一次的参数,而不是对每个输入行评估一次的参数。假设集合聚合是有序集合聚合的子类,其中一些直接参数需要在数量和数据类型上与聚合参数列匹配。这允许将那些直接自变量的值作为附加的“假设”行添加到集合输入行的集合中。有时可以通过查看索引而不是扫描每个输入行来优化单参数聚合函数(例如min或max)。 如果可以如此优化此聚合,请通过指定排序运算符进行指示。基本要求是,集合必须在运算符引起的排序顺序中产生第一个元素;换一种说法:
SELECT agg(col) FROM tab;
必须等于:
SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
进一步假设聚合函数将忽略
NULL
输入,并且当且仅当不存在非null输入时,它才会传递NULL
结果。通常,数据类型的<
运算符是MIN
的适当排序运算符,>
是MAX
的适当的排序运算符。请注意,除非指定的运算符是B树索引运算符类的“小于”或“大于”策略成员,否则优化实际上不会生效。为了能够创建聚合函数,必须对参数类型,状态类型和返回类型具有
USAGE
权限,并且对过渡和最终函数具有EXECUTE
权限。 - 参数
-
该SQL命令参数说明见下
name
- 要创建的聚合函数的名称(可以由模式指定)。
argmode
-
参数的模式:
IN
或VARIADIC
。 (聚合函数不支持OUT
参数。)如果省略,则默认值为IN
。只有最后一个参数可以标记为
VARIADIC
。 argname
- 参数的名称。当前这仅用于文档目的。如果省略,则参数没有名称。
arg_data_type
- 此聚合函数在其上操作的输入数据类型。 要创建零参数聚合函数,请写
*
代替参数说明列表(此类汇总的一个示例是count(*)
)。 base_type
- 在
CREATE AGGREGATE
的旧语法中,输入数据类型由basetype
参数指定,而不是写在聚合名称旁边。 请注意,此语法仅允许一个输入参数。 要使用此语法定义零参数聚合函数,请将basetype
指定为"ANY"
(不是*
)。 不能使用旧语法定义有序集的聚合。 sfunc
-
每个输入行要调用的状态转换函数的名称。 对于普通的N参数聚合函数,
sfunc
必须采用N + 1个参数,第一个参数为state_data_type
类型,其余参数与聚合的声明输入数据类型匹配。 该函数必须返回state_data_type
类型的值。 该函数获取当前状态值和当前输入数据值,并返回下一个状态值。对于有序集(包括假设集)聚合,状态转换函数仅接收当前状态值和聚合参数,而不接收直接参数。 否则它便与其他转移函数相同了。
state_data_type
- 聚合状态值的数据类型。
state_data_size
-
聚合状态值的近似平均大小(以字节为单位)。 如果省略此参数或将其设置为零,则基于
state_data_type
使用默认估计。优化器使用此值来估计分组聚合查询所需的内存。 此参数的较大值不鼓励使用哈希聚合。
ffunc
-
遍历所有输入行后,用于计算合计结果的最终函数的名称。 该函数必须采用
state_data_type
类型的单个参数。聚集的返回数据类型定义为该函数的返回类型。如果未指定
ffunc
,则将结束状态值用作汇总结果,返回类型为state_data_type
。 对于有序聚集(包括假设集合),最终函数不仅接收最终状态值,而且还接收所有直接参数的值。如果指定了
FINALFUNC_EXTRA
,则除了最终状态值和任何直接参数之外,最终函数还将接收与聚合的常规(聚合)参数相对应的额外NULL值。当定义多态聚合时,这主要用于允许正确解析聚合结果类型。
serialfunc
- 仅当
state_data_type
为internal
的聚合函数具有serialfunc
函数时,该函数才能参与并行聚合,该函数必须将聚合状态序列化为bytea
值以传输到另一个进程。 该函数必须接受一个类型为internal
的单个参数,并返回bytea
类型。 还需要相应的deserialfunc
。 deserialfunc
-
将先前序列化的聚合状态反序列化回
state_data_type
。此函数必须接受
bytea
和internal
类型的两个参数,并产生一个internal
类型的结果(注意:第二个internal
参数未使用,但出于类型安全的原因该参数是必需的)。 initial_condition
- 状态值的初始设置。 这必须是数据类型
state_data_type
接受的字符串常量。 如果未指定,则状态值开始为null。 msfunc
- 在移动聚合模式下要为每个输入行调用的前向状态转换函数的名称。与常规转换函数完全相同,除了它的第一个参数和结果的类型为
mstate_data_type
,这可能与state_data_type
不同。 minvfunc
-
在移动聚集模式下使用的逆状态转换函数的名称。该函数的参数和结果类型与
msfunc
相同,但是用于从当前聚合状态中删除一个值,而不是向其添加值。逆转换函数必须具有与前向状态转换函数相同的严格性属性。
mstate_data_type
- 使用移动聚合模式时,聚合状态值的数据类型。
mstate_data_size
- 使用移动聚合模式时,聚合状态值的近似平均大小(以字节为单位)。 这与
state_data_size
相同。 mffunc
-
使用移动聚合模式时,在遍历所有输入行之后将用来计算聚合结果的最终函数的名称。它与
ffunc
相同,不同之处在于其第一个参数的类型为mstate_data_type
,并且通过编写MFINALFUNC_EXTRA
指定了额外的伪参数。由
mffunc
或mstate_data_type
确定的聚合结果类型必须与由聚合的常规实现确定的结果类型匹配。 minitial_condition
- 使用移动聚合模式时,状态值的初始设置。这与
initial_condition
相同。 sort_operator
- 类似于
MIN
或MAX
的聚合的关联排序运算符。 这只是一个运算符名称(可以由模式指定)。 假定运算符具有与聚合相同的输入数据类型(必须是单参数常规聚合)。 HYPOTHETICAL
-
仅对于有序集合聚合,此标志指定将根据假设集合聚合的要求处理聚合参数: 也就是说,最后几个直接参数必须与聚合(
WITHIN GROUP
)参数的数据类型匹配。HYPOTHETICAL
标志对运行时行为没有影响,仅对数据类型的解析时解析和聚合参数的排序规则有影响。 combinefunc
-
组合函数的名称。 这是两个参数的函数,两个参数的类型均为
state_data_type
。必须返回state_data_type
类型的值。组合函数采用两个过渡状态值,并返回代表组合聚合的新过渡状态值。 在SeaboxMPP数据库中,如果以分段方式计算聚合函数的结果,则对各个内部状态调用合并函数,以将它们组合为结束内部状态。
注意,该函数在Executor内的哈希聚合模式下也被调用。 因此,如果您在没有合并函数的情况下调用此聚合函数,则永远不会选择哈希聚合。
由于哈希聚合非常有效,因此请考虑尽可能定义一个合并函数。
- 注解
-
必须先定义用于定义新聚合函数的普通函数。 请注意,在此版本的SeaboxMPP数据库中,要求将用于创建聚合的
sfunc
,ffunc
和Combinefunc
函数定义为IMMUTABLE
。配置参数
sc_enable_multiphase_agg
的值关闭,则仅执行单级聚合。用于自定义函数的所有已编译代码(共享库文件)必须放在SeaboxMPP数据库集群(Coordinator节点和所有Executor节点)中每个主机的相同位置。此位置也必须位于
LD_LIBRARY_PATH
中,以便服务器可以找到文件。可以使用以下语法将任何聚合称为有序聚合:
name ( arg [ , ... ] [ORDER BY sortspec [ , ...]] )
接受
ORDERED
关键字是为了实现向后兼容,但会被忽略。 - 示例
-
以下简单示例创建一个聚合函数,该函数计算两列的总和。
在创建聚合函数之前,创建两个用作聚合函数的
sfunc
和combinefunc
函数的函数。该函数在聚合函数中指定为
sfunc
函数。CREATE FUNCTION mysfunc_accum(numeric, numeric, numeric) RETURNS numeric AS 'select $1 + $2 + $3' LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT;
该函数在聚合函数中被指定为
combinefunc
函数。CREATE FUNCTION mycombine_accum(numeric, numeric ) RETURNS numeric AS 'select $1 + $2' LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT;
此
CREATE AGGREGATE
命令创建添加两列的聚合函数。CREATE AGGREGATE agg_prefunc(numeric, numeric) ( SFUNC = mysfunc_accum, STYPE = numeric, COMBINEFUNC = mycombine_accum, INITCOND = 0 );
以下命令创建一个表,添加一些行,并运行聚合函数。
create table t1 (a int, b int) DISTRIBUTED BY (a); insert into t1 values (10, 1), (20, 2), (30, 3); select agg_prefunc(a, b) from t1;
此
EXPLAIN
命令显示两阶段聚合。explain select agg_prefunc(a, b) from t1; QUERY PLAN -------------------------------------------------------------------------- Aggregate (cost=1.10..1.11 rows=1 width=32) -> Gather Motion 2:1 (slice1; Executors: 2) (cost=1.04..1.08 rows=1 width=32) -> Aggregate (cost=1.04..1.05 rows=1 width=32) -> Seq Scan on t1 (cost=0.00..1.03 rows=2 width=8) (4 rows)
- 兼容性说明
CREATE AGGREGATE
是SeaboxMPP数据库语言的扩展。 SQL标准不提供用户定义的聚合函数。- 相关SQL命令
ALTER AGGREGATE
,DROP AGGREGATE
,CREATE FUNCTION