↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3

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

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;

报告文档问题

阅读 上游文档. 通过 PostgreSQL 文档反馈表单.