F.23. intagg#

F.23. intagg

F.23. intagg

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

F.23.1. Функции

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

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

F.23.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;