高效合并(删除重复项)数组


10

我有两个表,left2right2。两个表都将很大(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);

我将执行这种类型的查询:

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;

在哪里聚集数组,我使用以下函数:

CREATE AGGREGATE array_agg_mult(anyarray) (
SFUNC=array_cat,
STYPE=anyarray,
INITCOND='{}');

连接数组后,我将使用模块的UNIQ功能intarray。有更有效的方法吗?arr字段上是否有任何索引来加快合并速度(删除重复项)?聚合函数可以直接删除重复项吗?如果有帮助,可以将原始数组视为已排序(并且它们是唯一的)。

SQL小提琴在这里


您要一次查询数百万行吗?您如何处理结果?还是会有谓词选择一些?可以right2.arr 像演示模式所建议的那样为NULL吗?您是否需要排序数组?
Erwin Brandstetter 2015年

Answers:


9

结果正确吗?

首先:正确性。您想产生一组独特的元素吗?您当前的查询不执行该操作。该功能uniq()intarray模块只承诺:

删除相邻的重复项

手册中所述,您将需要:

SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM   ...

还给您排序后的数组-假设您想要的话,您无需弄清。

我看你 sort()你的小提琴,所以这可能只是你的问题中一个错字。

Postgres 9.5

无论哪种方式,您都会喜欢新的Postgres 9.5(当前为beta)。它提供了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;

这也解决了您的问题:

聚合函数可以直接删除重复项吗?

是的,可以DISTINCT。但这并没有比uniq()针对整数数组进行了优化的整数数组快,而DISTINCT对于所有符合条件的数据类型都是通用的。

不需要intarray模块。但是,结果不一定要排序。Postgres DISTINCT(IIRC)使用不同的算法,通常对大集合进行哈希处理,然后对结果进行排序,除非您添加explicit ORDER BY。如果需要排序的数组,可以ORDER BY直接添加到聚合函数中:

array_agg(DISTINCT elem ORDER BY elem)

但这通常比将预排序的数据馈送到(一个大类与许多小类)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;

在我对Postgres 9.4的粗略测试中,这是最快的变体。

基于您提供的 SQL Fiddle

指数

我认为这里没有任何潜力。唯一的选择是:

CREATE INDEX ON right2 (t1, arr);

仅当您从中获得仅索引扫描时才有意义-如果基础表right2的宽度比这两列大得多,并且您的设置有资格进行仅索引扫描,则将发生这种情况。Postgres Wiki中的详细信息。


谢谢+1。无论如何,我以后都必须UNNEST,但是要检查是否要删除阵列中的重复项,然后UNNEST会更快。
亚历山德罗斯

0

我真的很失望,这在Microsoft Access中很容易做到。您可以创建“删除重复项”查询,然后查看SQL以查看其运行情况。我必须启动Windows机器才能查看。它们各不相同,查询向导可以做到。

我认为有效的一件事是将所有数据加载到一个表中,然后将SELECT DISTINCT加载到新表中。您也可以在使用order by子句时坚持使用。我一年前就做到了,一定是这样。

我合并了2年的温度数据,传感器每分钟发送2个相同数据点的副本作为冗余保护措施。有时一个人被丢了,但我只想保留一个。文件之间也有重叠。

如果数据在整个运行过程中的格式完全相同,则在UNIX计算机上,您可以执行以下操作

cat *.tab > points.txt
sort -n < points.txt > sorted.txt
uniq -u sorted.txt unique.txt

但是uniq会将行作为字符串进行比较,例如18.7000与18.7不同。我在两年内更换了软件,因此同时拥有两种格式。


对Postgres感到失望?Access甚至有数组吗?
ypercubeᵀᴹ

我不知道,但是它可以删除重复项,这在数据清理中是很常见的问题。选择非重复就足够接近了。您并不总是可以控制现实世界中的原始数据。
艾伦·科里
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.