F.18. intagg — agregador y enumerador de enteros #

F.18.1. Funciones
F.18.2. Ejemplos de uso

El módulo intagg proporciona un agregador y un enumerador de enteros. intagg ahora está obsoleto, ya que existen funciones integradas que ofrecen un superconjunto de sus capacidades. Sin embargo, el módulo se sigue proporcionando como un adaptador de compatibilidad alrededor de las funciones integradas.

F.18.1. Funciones #

El agregador es una función de agregación int_array_aggregate(integer) que produce un array de enteros que contiene exactamente los enteros que se le pasan. Es un adaptador alrededor de array_agg, que hace lo mismo para cualquier tipo de array.

El enumerador es una función int_array_enum(integer[]) que devuelve setof integer. Es esencialmente la operación inversa del agregador: dado un array de enteros, lo expande en un conjunto de filas. Es un adaptador alrededor de unnest, que hace lo mismo para cualquier tipo de array.

F.18.2. Ejemplos de uso #

Muchos sistemas de bases de datos tienen la noción de una tabla de muchos a muchos. Tal tabla usualmente se encuentra entre dos tablas indexadas, por ejemplo:

CREATE TABLE left_table  (id INT PRIMARY KEY, ...);
CREATE TABLE right_table (id INT PRIMARY KEY, ...);
CREATE TABLE many_to_many(id_left  INT REFERENCES left_table,
                          id_right INT REFERENCES right_table);

Típicamente se usa así:

SELECT right_table.*
FROM right_table JOIN many_to_many ON (right_table.id = many_to_many.id_right)
WHERE many_to_many.id_left = item;

Esto devolverá todos los elementos en la tabla derecha para una entrada en la tabla izquierda. Esta es una construcción muy común en SQL.

Ahora, esta metodología puede ser ineficiente con un número muy grande de entradas en la tabla many_to_many. A menudo, una unión como esta resultaría en un escaneo de índice y una lectura por cada entrada de la derecha en la tabla para una entrada de la izquierda en particular. Si tienes un sistema muy dinámico, no hay mucho que puedas hacer. Sin embargo, si tienes datos que son bastante estáticos, puedes crear una tabla de resumen con el agregador.

CREATE TABLE summary AS
  SELECT id_left, int_array_aggregate(id_right) AS rights
  FROM many_to_many
  GROUP BY id_left;

Esto creará una tabla con una fila por cada elemento izquierdo, y un array de elementos derechos. Ahora, esto es bastante inútil sin alguna forma de usar el array; es por eso que existe un enumerador de arrays. Puedes hacer:

SELECT id_left, int_array_enum(rights) FROM summary WHERE id_left = item;

La consulta anterior usando int_array_enum produce los mismos resultados que:

SELECT id_left, id_right FROM many_to_many WHERE id_left = item;

La diferencia es que la consulta contra la tabla de resumen solo tiene que obtener una fila de la tabla, mientras que la consulta directa contra many_to_many debe realizar un escaneo de índice y obtener una fila por cada entrada.

En un sistema, un EXPLAIN mostró que una consulta con un costo de 8488 se redujo a un costo de 329. La consulta original era una unión que involucraba a la tabla many_to_many, que fue reemplazada por:

SELECT id_right, count(id_right) FROM
  ( SELECT id_left, int_array_enum(rights) AS id_right
    FROM summary
    JOIN (SELECT id FROM left_table
          WHERE id = item) AS lefts
    ON (summary.id_left = lefts.id)
  ) AS list
  GROUP BY id_right
  ORDER BY count DESC;