问题报告 纠错本页面

F.17. intagg

intagg模块提供一个整数聚合器和一个枚举器。intagg 现在已经废弃了,因为内置的函数提供它的能力的一个超集。不过, 该模块仍然作为内置函数的兼容性封装器提供。

F.17.1. 函数

聚合器是一个生产正好包含输入的整数的整数数组的聚合函数int_array_aggregate(integer)。 这是array_agg的封装器,array_agg对于任意数组类型做相同的事情。

枚举器是返回setof integer类型的函数int_array_enum(integer[])。 本质上是聚合器的反向操作:给出一个整数数组,将其展开为一组行。 这是unnest的封装器,unnest对于任意数组类型做相同的事情。

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

不同之处是针对summary表的查询必须只从表中获取一行,而针对one_to_many 的直接查询必须索引扫描然后从每条记录中获取一行。

在一个系统上,一个显示了消耗8488的查询的EXPLAIN减少到消耗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;