intagg 模块提供一个整数聚合器和一个枚举器。 由于已经有内置函数提供了其能力的超集,所以 intagg 现已过时。 不过,该模块仍作为这些内置函数的兼容性包装器提供。
聚合器是聚合函数int_array_aggregate(integer), 它会生成一个整数数组,其中恰好包含输入给它的那些整数。 这是对array_agg的包装器,后者对任意数组类型都能做同样的事情。
枚举器是函数int_array_enum(integer[]), 它返回setof integer。本质上,它是聚合器的逆操作: 给定一个整数数组,将其展开为一组行。 这是对unnest的包装器,后者对任意数组类型都能做同样的事情。
许多数据库系统都有多对多表这一概念。这样的表通常位于两个带索引的表之间,例如:
CREATE TABLE left_table (id INT PRIMARY KEY, ...);
CREATE TABLE right_table (id INT PRIMARY KEY, ...);
CREATE TABLE many_to_many(id_left INT REFERENCES left_table,
id_right INT REFERENCES right_table);
它通常按如下方式使用:
SELECT right_table.*
FROM right_table JOIN many_to_many ON (right_table.id = many_to_many.id_right)
WHERE many_to_many.id_left = item;
这将返回左侧表中某个条目在右侧表中对应的所有条目。 这是 SQL 中非常常见的一种构造。
但是,如果many_to_many表中的条目非常多, 这种方法就会变得相当繁琐。通常,对于左侧表中的某个特定条目, 右侧表中的每个对应条目都要执行一次索引扫描并取回一行。 如果你的系统非常动态,那就没有太多办法。不过,如果有一部分数据相当静态, 你可以借助聚合器创建一个汇总表。
CREATE TABLE summary AS SELECT id_left, int_array_aggregate(id_right) AS rights FROM many_to_many GROUP BY id_left;
这样会创建一个表,其中左侧每个条目对应一行,并附带一个由右侧条目组成的数组。 不过,如果没有某种使用该数组的方法,它就几乎没有用处;这正是数组枚举器存在的原因。 你可以这样做:
SELECT id_left, int_array_enum(rights) FROM summary WHERE id_left = item;
上面这个使用int_array_enum的查询,产生的结果与下面的查询相同:
SELECT id_left, id_right FROM many_to_many WHERE id_left = item;
区别在于,针对汇总表的查询只需要从表中取出一行, 而直接查询many_to_many则必须对每个条目都进行索引扫描并取回一行。
在某个系统上,EXPLAIN显示,某个查询的代价从 8488 降到了 329。 原始查询是一个涉及many_to_many表的连接,后来被替换为:
SELECT id_right, count(id_right) FROM
( SELECT id_left, int_array_enum(rights) AS id_right
FROM summary
JOIN (SELECT id FROM left_table
WHERE id = item) AS lefts
ON (summary.id_left = lefts.id)
) AS list
GROUP BY id_right
ORDER BY count DESC;
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。