CREATE AGGREGATE
Определяет новую агрегатную функцию.
Синтаксис
CREATE AGGREGATE <name> ( [ <argmode> ] [ <argname> ] <arg_data_type> [ , ... ] ) (
SFUNC = <statefunc>,
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 = <statefunc>,
STYPE = <state_data_type>
[ , SSPACE = <state_data_size> ]
[ , FINALFUNC = <ffunc> ]
[ , FINALFUNC_EXTRA ]
[ , COMBINEFUNC = <combinefunc> ]
[ , SERIALFUNC = <serialfunc> ]
[ , DESERIALFUNC = <deserialfunc> ]
[ , INITCOND = <initial_condition> ]
[ , HYPOTHETICAL ]
)
Устаревший синтаксис:
CREATE AGGREGATE <name> (
BASETYPE = <base_type>,
SFUNC = <statefunc>,
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 определяет новую агрегатную функцию.
В Greengage DB уже предусмотрены некоторые базовые и часто используемые агрегатные функции, такие как count, min, max, sum, avg и другие.
Если вы определяете новые типы или требуется агрегатная функция, которая еще не предусмотрена, вы можете использовать CREATE AGGREGATE для создания необходимых функций.
Если указано имя схемы (например, CREATE AGGREGATE myschema.myagg …), то агрегатная функция создается в указанной схеме.
В противном случае она создается в текущей схеме.
Агрегатная функция идентифицируется своим именем и типами входных данных. Две агрегатные функции в одной схеме могут иметь одинаковое имя, если они работают с разными входными типами. Имя и типы входных данных агрегатной функции также должны отличаться от имени и типов входных данных каждой обычной функции в той же схеме. Такое поведение идентично перегрузке имен обычных функций. См. CREATE FUNCTION.
Простая агрегатная функция состоит из одной, двух или трех обычных функций (которые должны быть помечены как IMMUTABLE):
-
функция перехода состояния (state transition function)
statefunc; -
необязательная функция финального вычисления (final calculation function)
ffunc; -
необязательная функция объединения (combine function)
combinefunc.
Эти функции используются следующим образом:
<statefunc>( internal-state, next-data-values ) ---> next-internal-state
<ffunc>( internal-state ) ---> aggregate-value
<combinefunc>( internal-state, internal-state ) ---> next-internal-state
Greengage DB создает временную переменную типа данных state_data_type для хранения текущего внутреннего состояния агрегатной функции.
Для каждой входной строки вычисляются значения аргументов агрегата, и вызывается функция перехода состояния с текущим значением состояния и новыми значениями аргументов для вычисления нового значения внутреннего состояния.
После обработки всех строк один раз вызывается финальная функция для вычисления возвращаемого значения агрегата.
Если финальная функция отсутствует, то конечное значение состояния возвращается как есть.
Если вы пишете пользовательскую агрегатную функцию на C и объявляете значение состояния (state_data_type) как тип internal, существует риск возникновения ошибки нехватки памяти (out-of-memory).
Если значения состояния internal не управляются должным образом и запрос требует слишком много памяти для значений состояния, может возникнуть ошибка нехватки памяти.
Чтобы предотвратить это, используйте mpool_alloc(mpool, size), чтобы Greengage DB управлял памятью и выделял ее для не временных значений состояния, то есть значений состояния, которые живут в течение всей агрегации.
Аргумент mpool функции mpool_alloc() — это aggstate→hhashtable→group_buf.
Пример см. в реализации агрегатов числовых типов данных в репозитории Greengage DB в файле src/backend/utils/adt/numeric.c.
Вы можете указать combinefunc как метод для оптимизации выполнения агрегатной функции.
Указав combinefunc, агрегатную функцию можно запускать параллельно сначала на сегментах, а затем на мастере.
При выполнении двухуровневого выполнения statefunc запускается на сегментах для генерации частичных результатов агрегации, а combinefunc запускается на мастере для агрегации частичных результатов с сегментов.
Если выполняется одноуровневая агрегация, все строки отправляются на мастер, и к строкам применяется statefunc.
Одноуровневая агрегация и двухуровневая агрегация являются эквивалентными стратегиями выполнения.
Любой тип агрегации может быть реализован в плане запроса.
Когда вы реализуете функции combinefunc и statefunc, вы должны гарантировать, что вызов statefunc на экземплярах сегментов с последующим вызовом combinefunc на мастере дает тот же результат, что и одноуровневая агрегация, которая отправляет все строки на мастер, а затем применяет к строкам только statefunc.
Агрегатная функция может предоставлять необязательное начальное условие — начальное значение для внутреннего значения состояния.
Оно указывается и хранится в базе данных как значение типа text, но должно быть допустимым внешним представлением константы типа данных значения состояния.
Если оно не указано, значение состояния изначально равно NULL.
Если функция statefunc объявлена как STRICT, то она не может быть вызвана с входными значениями NULL.
С такой функцией перехода выполнение агрегатной функции ведет себя следующим образом.
Строки с любыми входными значениями NULL игнорируются (функция не вызывается, и сохраняется предыдущее значение состояния).
Если начальное значение состояния равно NULL, то при первой строке со всеми значениями, отличными от NULL, первое значение аргумента заменяет значение состояния, и функция перехода вызывается для последующих строк со всеми значениями, отличными от NULL.
Это полезно для реализации агрегатов, таких как max.
Обратите внимание, что такое поведение доступно только тогда, когда state_data_type совпадает с первым arg_data_type.
Когда эти типы различаются, вы должны предоставить начальное условие, отличное от NULL, или использовать нестрогую (nonstrict) функцию перехода.
Если функция statefunc не объявлена как STRICT, то она будет вызываться безусловно для каждой входной строки и должна самостоятельно обрабатывать входные значения NULL и значения состояния NULL.
Это позволяет автору агрегатной функции иметь полный контроль над обработкой значений NULL в агрегате.
Если финальная функция (ffunc) объявлена как STRICT, то она не будет вызвана, когда конечное значение состояния равно NULL; вместо этого результат NULL будет возвращен автоматически.
Это нормальное поведение функций STRICT.
В любом случае финальная функция имеет возможность вернуть значение NULL.
Например, финальная функция для avg возвращает NULL, когда видит, что было ноль входных строк.
Иногда полезно объявить финальную функцию, принимающую не только значение состояния, но и дополнительные параметры, соответствующие входным значениям агрегата.
Основная причина для этого — если финальная функция полиморфна, и типа данных значения состояния недостаточно для определения типа результата.
Эти дополнительные параметры всегда передаются как NULL (поэтому финальная функция не должна быть строгой при использовании опции FINALFUNC_EXTRA), но тем не менее они являются валидными параметрами.
Финальная функция может, например, использовать get_fn_expr_argtype для идентификации фактического типа аргумента в текущем вызове.
Агрегатная функция может при необходимости поддерживать режим скользящего агрегата (moving-aggregate mode), как описано в разделе Moving-Aggregate Mode документации PostgreSQL.
Для этого требуется указать функции msfunc, minvfunc и mstype, а также опционально функции mspace, mfinalfunc, mfinalfunc_extra и minitcond.
За исключением minvfunc, эти функции работают как соответствующие функции простого агрегата без префикса m; они определяют отдельную реализацию агрегата, которая включает обратную функцию перехода.
Синтаксис с ORDER BY в списке параметров создает специальный тип агрегата, называемый агрегатом упорядоченного набора (ordered-set aggregate); или, если указано HYPOTHETICAL, создается агрегат гипотетического набора (hypothetical-set aggregate).
Эти агрегаты работают с группами отсортированных значений зависимым от порядка способом, поэтому указание порядка сортировки входных данных является неотъемлемой частью вызова.
Кроме того, они могут иметь прямые (direct) аргументы, которые оцениваются только один раз на агрегацию, а не один раз для каждой входной строки.
Агрегаты гипотетического набора — это подкласс агрегатов упорядоченного набора, в котором некоторые прямые аргументы должны соответствовать по количеству и типам данных агрегируемым столбцам аргументов.
Это позволяет добавлять значения этих прямых аргументов к коллекции строк ввода агрегата как дополнительную "гипотетическую" строку.
Агрегатные функции с одним аргументом, такие как min или max, иногда можно оптимизировать, обращаясь к индексу, вместо того чтобы сканировать каждую входную строку.
Если данную агрегатную функцию можно так оптимизировать, укажите это, задав оператор сортировки (sort operator).
Основное требование заключается в том, что агрегатная функция должна выдавать первый элемент в порядке сортировки, заданном оператором.
Другими словами, выражение:
SELECT <agg>(<col>) FROM <tab>;
должно быть эквивалентно:
SELECT <col> FROM <tab> ORDER BY <col> USING <sortop> LIMIT 1;
Дальнейшие предположения заключаются в том, что агрегатная функция игнорирует входные данные NULL и выдает результат NULL тогда и только тогда, когда не было входных данных, отличных от NULL.
Обычно оператор < типа данных является правильным оператором сортировки для MIN, а > — правильным оператором сортировки для MAX.
Обратите внимание, что оптимизация на самом деле не сработает, если указанный оператор не является членом стратегии "меньше чем" или "больше чем" класса операторов B-tree индекса.
Чтобы иметь возможность создать агрегатную функцию, вы должны иметь привилегию USAGE для типов аргументов, типаов состояния и типа возвращаемого значения, а также привилегию EXECUTE для функций перехода и финальных функций.
Параметры
| Параметр | Описание |
|---|---|
name |
Имя (опционально указанное со схемой) создаваемой агрегатной функции |
argmode |
Режим аргумента: |
argname |
Имя аргумента. В настоящее время это полезно только для целей документации. Если не указано, аргумент не имеет имени |
arg_data_type |
Тип входных данных, с которым работает эта агрегатная функция.
Чтобы создать агрегатную функцию без аргументов, укажите |
base_type |
В старом синтаксисе для |
statefunc |
Имя функции перехода состояния, вызываемой для каждой входной строки.
Для обычной агрегатной функции с N аргументами функция перехода состояния Для агрегатов упорядоченного набора (включая гипотетический набор) функция перехода состояния |
state_data_type |
Тип данных для значения состояния агрегата |
state_data_size |
Приблизительный средний размер (в байтах) значения состояния агрегата.
Если этот параметр не указан или равен нулю, используется оценка по умолчанию на основе |
ffunc |
Имя финальной функции, вызываемой для вычисления результата агрегата после прохождения всех входных строк.
Функция должна принимать один аргумент типа Для агрегатов упорядоченного набора (включая гипотетический набор) финальная функция получает не только конечное значение состояния, но и значения всех прямых аргументов. Если указан |
combinefunc |
Имя функции объединения (combine function).
Это функция двух аргументов, оба типа Обратите внимание, что эта функция также вызывается в режиме хеш-агрегации внутри сегмента. Поэтому, если вы вызываете эту агрегатную функцию без функции объединения, хеш-агрегация никогда не выбирается. Поскольку хеш-агрегация эффективна, рассмотрите возможность определения функции объединения, когда это возможно |
serialfunc |
Агрегатная функция, у которой |
deserialfunc |
Десериализует ранее сериализованное состояние агрегата обратно в ПРИМЕЧАНИЕ
Второй аргумент |
initial_condition |
Начальная настройка для значения состояния.
Это должна быть строковая константа в форме, принимаемой для типа данных |
msfunc |
Имя функции прямого перехода состояния, вызываемой для каждой входной строки в режиме скользящего агрегата.
Это такая же функция, что и обычная функция перехода, за исключением того, что ее первый аргумент и результат имеют тип |
minvfunc |
Имя функции обратного перехода состояния, используемой в режиме скользящего агрегата.
Эта функция имеет те же типы аргументов и результатов, что и |
mstate_data_type |
Тип данных для значения состояния агрегата при использовании режима скользящего агрегата |
mstate_data_size |
Приблизительный средний размер (в байтах) значения состояния агрегата при использовании режима скользящего агрегата.
Работает так же, как |
mffunc |
Имя финальной функции, вызываемой для вычисления результата агрегата после прохождения всех входных строк при использовании режима скользящего агрегата.
Работает так же, как |
minitial_condition |
Начальная настройка для значения состояния при использовании режима скользящего агрегата.
Работает так же, как |
sort_operator |
Связанный оператор сортировки для агрегата типа |
HYPOTHETICAL |
Только для агрегатов упорядоченного набора этот флаг указывает, что аргументы агрегата должны обрабатываться в соответствии с требованиями для агрегатов гипотетического набора: то есть последние несколько прямых аргументов должны соответствовать типам данных агрегируемых ( |
Примечания
Обычные функции, используемые для определения новой агрегатной функции, должны быть определены первыми.
Нет необходимости в том, чтобы функции statefunc, ffunc и combinefunc, используемые для создания агрегата, были определены как IMMUTABLE.
Если значение конфигурационного параметра сервера Greengage DB gp_enable_multiphase_agg равно off, выполняется только одноуровневая агрегация.
Любой скомпилированный код (файлы разделяемых библиотек) для пользовательских функций должен быть размещен в одном и том же месте на каждом хосте в кластере Greengage DB (мастер и все сегменты).
Это местоположение также должно быть в LD_LIBRARY_PATH, чтобы сервер мог найти файлы.
Любую агрегатную функцию можно вызвать как упорядоченный агрегат, используя синтаксис:
name ( arg [ , ... ] [ORDER BY sortspec [ , ...]] )
Ключевое слово ORDERED принимается для обратной совместимости, но игнорируется.
В качестве синонима для COMBINEFUNC можно использовать ключевое слово PREFUNC, которое поддерживается для обратной совместимости.
Примеры
Следующий пример создает агрегатную функцию, которая вычисляет сумму двух столбцов.
Перед созданием агрегатной функции создайте две функции, которые используются как функции statefunc и combinefunc агрегатной функции.
Следующая функция указывается как функция statefunc в агрегатной функции:
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; segments: 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)
Optimizer: Pivotal Optimizer (GPORCA)
(5 rows)
Совместимость
CREATE AGGREGATE является расширением языка Greengage DB.
Стандарт SQL не предусматривает пользовательских агрегатных функций.