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;