Ale*_*ros 11 postgresql aggregate array postgresql-9.3
我有两张桌子,left2
和right2
。两个表都会很大(1-10M 行)。
CREATE TABLE left2(id INTEGER, t1 INTEGER, d INTEGER);
ALTER TABLE left2 ADD PRIMARY KEY (id,t1);
CREATE TABLE right2( t1 INTEGER, d INTEGER, arr INTEGER[] );
ALTER TABLE right2 ADD PRIMARY KEY(t1,d);
Run Code Online (Sandbox Code Playgroud)
我将执行这种类型的查询:
SELECT l.d + r.d,
UNIQ(SORT((array_agg_mult(r.arr)))
FROM left2 l,
right2 r
WHERE l.t1 = r.t1
GROUP BY l.d + r.d
ORDER BY l.d + r.d;
Run Code Online (Sandbox Code Playgroud)
在哪里聚合数组我使用函数:
CREATE AGGREGATE array_agg_mult(anyarray) (
SFUNC=array_cat,
STYPE=anyarray,
INITCOND='{}');
Run Code Online (Sandbox Code Playgroud)
连接数组后,我使用模块的UNIQ
功能intarray
。有没有更有效的方法来做到这一点?该arr
字段上是否有任何索引可以加速合并(删除重复项)?聚合函数可以直接去除重复吗?如果有帮助,可以将原始数组视为已排序(并且它们是唯一的)。
SQL小提琴在这里:
Erw*_*ter 10
首先:正确性。您想生成一组唯一元素吗?您当前的查询没有这样做。该功能uniq()
从intarray模块只承诺:
删除相邻的重复项
就像手册中的说明一样,您需要:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
Run Code Online (Sandbox Code Playgroud)
还给你排序的数组 - 假设你想要,你没有澄清。
我看你有 sort()
你的小提琴,所以这可能只是你的问题中一个错字。
无论哪种方式,由于 Postgres 9.5array_agg()
具有我array_agg_mult()
内置的开箱即用功能,而且速度也更快:
阵列处理方面也有其他性能改进。
的主要目的array_agg_mult()
是聚合多维数组,但无论如何你只能生成一维数组。所以我至少会尝试这个替代查询:
SELECT l.d + r.d AS d_sum, array_agg(DISTINCT elem) AS result_arr
FROM left2 l
JOIN right2 r USING (t1)
, unnest(r.arr) elem
GROUP BY 1
ORDER BY 1;
Run Code Online (Sandbox Code Playgroud)
这也解决了您的问题:
聚合函数可以直接去除重复吗?
是的,它可以,与DISTINCT
。但这并不比uniq()
整数数组快,整数数组已经针对整数数组进行了优化,而DISTINCT
对于所有符合条件的数据类型都是通用的。
不需要intarray
模块。但是,结果不一定要排序。Postgres 对DISTINCT
. 大集通常是散列的,除非您添加显式,否则结果将保持未排序ORDER BY
。如果需要排序数组,可以ORDER BY
直接添加到聚合函数中:
array_agg(DISTINCT elem ORDER BY elem)
Run Code Online (Sandbox Code Playgroud)
但这通常比将预先排序的数据提供给(一个大排序对许多小排序)要慢array_agg()
。所以我会在子查询中排序,然后聚合:
SELECT d_sum, uniq(array_agg(elem)) AS result_arr
FROM (
SELECT l.d + r.d AS d_sum, elem
FROM left2 l
JOIN right2 r USING (t1)
, unnest(r.arr) elem
ORDER BY 1, 2
) sub
GROUP BY 1
ORDER BY 1;
Run Code Online (Sandbox Code Playgroud)
这是我对 Postgres 9.4 的粗略测试中最快的变体。
SQL Fiddle基于您提供的那个。
我认为这里没有任何索引的潜力。唯一的选择是:
CREATE INDEX ON right2 (t1, arr);
Run Code Online (Sandbox Code Playgroud)
仅当您从中获得仅索引扫描时才有意义 - 如果基础表right2
比这两个列宽得多并且您的设置符合仅索引扫描的条件,则会发生这种情况。Postgres Wiki 中的详细信息。