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