F.20. intagg — агрегатор и перечислитель целых чисел#

F.20. intagg — агрегатор и перечислитель целых чисел

F.20. intagg — агрегатор и перечислитель целых чисел #

Модуль intagg предоставляет агрегатор целых чисел и перечислитель. intagg теперь устарел, поскольку существуют встроенные функции, которые предоставляют набор возможностей, превосходящий его. Однако модуль все еще предоставляется в качестве оболочки совместимости для встроенных функций.

F.20.1. Функции #

Агрегатор - это агрегатная функция int_array_aggregate(integer) которая создает целочисленный массив содержащий ровно те целые числа, которые ему подаются. Это обертка вокруг array_agg, которая делает то же самое для любого типа массива.

Перечислитель - это функция int_array_enum(integer[]), которая возвращает setof integer. Она является, по сути, обратной операцией агрегатора: заданному массиву целых чисел она расширяет его в набор строк. Это обертка вокруг функции unnest, которая выполняет то же самое для любого типа массива.

F.20.2. Примеры использования #

Многие системы баз данных имеют понятие таблицы один ко многим. Такая таблица обычно находится между двумя индексированными таблицами, например:

CREATE TABLE left (id INT PRIMARY KEY, ...);
CREATE TABLE right (id INT PRIMARY KEY, ...);
CREATE TABLE one_to_many(left INT REFERENCES left, right INT REFERENCES right);

Обычно он используется так:

SELECT right.* from right JOIN one_to_many ON (right.id = one_to_many.right)
  WHERE one_to_many.left = item;

Это вернет все элементы в правой таблице для записи в левой таблице. Это очень распространенная конструкция в SQL.

Теперь, эта методология может быть громоздкой при очень большом количестве записей в таблице one_to_many. Часто, такое соединение приводит к сканированию индекса и извлечению для каждой записи справа в таблице для определенной записи слева. Если у вас очень динамичная система, то мало что можно сделать. Однако, если у вас есть некоторые данные, которые достаточно статичны, вы можете создать сводную таблицу с помощью агрегатора.

CREATE TABLE summary AS
  SELECT left, int_array_aggregate(right) AS right
  FROM one_to_many
  GROUP BY left;

Это создаст таблицу с одной строкой для каждого левого элемента и массивом правых элементов. Теперь это довольно бесполезно без способа использования массива; вот почему есть перечислитель массива. Вы можете сделать

SELECT left, int_array_enum(right) FROM summary WHERE left = item;

Вышеуказанный запрос, использующий функцию int_array_enum, дает те же результаты, что и

SELECT left, right FROM one_to_many WHERE left = item;

Разница заключается в том, что запрос к сводной таблице должен получить только одну строку из таблицы, в то время как прямой запрос к one_to_many должен выполнить индексное сканирование и извлечь строку для каждой записи.

На одной системе EXPLAIN показал запрос с затратами 8488, которые были снижены до 329. Исходный запрос был соединением, включающим таблицу one_to_many, которая была заменена на:

SELECT right, count(right) FROM
  ( SELECT left, int_array_enum(right) AS right
    FROM summary JOIN (SELECT left FROM left_table WHERE left = item) AS lefts
         ON (summary.left = lefts.left)
  ) AS list
  GROUP BY right
  ORDER BY count DESC;