我有一张包含1.5 MM
条记录的表格。每条记录都有row number
和array
,数组之间有1 and 1,000
个元素。我试图找到所有大型数组子集的数组。
当我使用下面的代码时,我得到错误:语句需要比资源队列允许的资源更多的资源(可能因为有超过一万亿种可能的组合):
select
a.array as dup
from
table a
left join
table b
on
b.array @> a.array
and a.row_number <> b.row_number
是否有更有效的方法来识别哪些数组是其他数组的子集并将其标记为删除而不是使用@>
?
答案 0 :(得分:0)
好吧,如果没有索引的适当支持,我不会在单个声明性SQL语句中看到如何有效地执行此操作。我不知道这对GIN索引的效果如何,但使用GIN索引肯定会避免需要比较每一对可能的行。
我要做的第一件事就是仔细调查您可以使用的索引类型,并尝试根据需要创建索引。
如果这不起作用,从程序上讲,我首先想到的是对所有数组进行排序,然后将行排序为数组上的分级字典顺序。然后从最短的数组开始,并按如下方式向上工作:例如对于[1,4,9],检查长度为&lt; = 3的所有数组,如果它们是子集,则以1开头,然后检查长度为&lt; = 2且以4开头的所有数组,然后检查所有数组长度&lt; = 1以9开头,在你去的时候去掉任何找到的子集,这样你就不会一遍又一遍地重新检查相同的行。
我确信你可以稍微调整一下这个算法,特别是取决于所涉及数据的特定性质。如果有更好的算法,我不会感到惊讶;这只是我想到的第一件事。您可以从此算法向后工作到所需的SQL,或者您可能必须转储表以进行客户端处理或其混合。
答案 1 :(得分:0)
您的示例代码表明您只对查找表中另一行中任何其他数组的子集的数组感兴趣。
但是,使用JOIN
的查询会返回所有组合,可能会使结果倍增。
尝试EXISTS
半连接,仅返回符合条件的行一次:
SELECT a.array as dup
FROM table a
WHERE EXISTS (
SELECT 1
FROM table b
WHERE a.array <@ b.array
AND a.row_number <> b.row_number
);
使用此表单,Postgres可以在找到第一个匹配项后立即停止迭代行。如果这两者都没有,请尝试分区您的查询。添加像
这样的子句AND table_id BETWEEN 0 AND 10000
并遍历表格。对这种情况应该有效。
除此之外:遗憾的是你的派生(Greenplum)似乎不支持GIN索引,这会使这个操作更快。 (但索引本身会很大)