Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16

F.19. intagg — 整数聚合器和枚举器 #

F.19.1. 函数
F.19.2. 使用示例

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

F.19.1. 函数 #

聚合器是一个聚合函数 int_array_aggregate(integer),它生成一个包含其接收到的所有整数的整数数组。这是 array_agg 的一个包装器,它对任何数组类型执行相同操作。

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

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