Postgresql 中文操作指南

F.19. intagg — integer aggregator and enumerator #

intagg 模块提供一个整数聚合器和一个枚举器。intagg 现已过时,因为有内置函数提供其功能的超集。然而,模组仍然作为内置函数的兼容性包装而提供。

F.19.1. Functions #

聚合器是一个聚合函数 int_array_aggregate(integer),产生一个包含其被喂入的每个整数的整数数组。这是 array_agg 的一个包装,array_agg 对任何数组类型执行相同操作。

枚举器是一个返回 setof integer 的函数 int_array_enum(integer[])。它本质上是聚合器的反向操作:给定一个整数数组,将其展开到一组行中。这是一个包装器,适用于 unnest,它对任何数组类型都会执行相同操作。

F.19.2. Sample Uses #

许多数据库系统都具有多对一表的概念。这种表通常位于两个索引表之间,例如:

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;