Postgres:优化庞大的GROUP BY

时间:2019-01-10 13:56:52

标签: postgresql optimization query-optimization aggregation

我有这样一张桌子:

CREATE TABLE values (first_id varchar(26), sec_id int, mode varchar(6), external1_id varchar(23), external2_id varchar(26), x int, y int);

可能有多个具有相同first_id的值,我的目标是将每个first_id(所有相关行)展平(放入json)到另一个表中。

我这样做:

INSERT INTO othervalues(first_id, results)
  SELECT first_id, json_agg(values) AS results FROM values GROUP BY first_id;

在结果列中,我具有所有行的json数组,以后可以按原样使用。

我的问题是,这非常慢,并且有一个巨大的表:值大约有1亿行,这使我的计算机(我实际上是在本地测试)的速度变慢,直到它消失(这是Ubuntu)。

使用EXPLAIN,我发现它是使用GroupPartitioner的,

SET work_mem = '1GB';

现在它使用了HashPartitioner,但这仍然会杀死我的计算机。一个解释给我:

Insert on othervalues  (cost=2537311.89..2537316.89 rows=200 width=64)
  ->  Subquery Scan on "*SELECT*"  (cost=2537311.89..2537316.89 rows=200 width=64)
        ->  HashAggregate  (cost=2537311.89..2537314.39 rows=200 width=206)
              ->  Seq Scan on values  (cost=0.00..2251654.26 rows=57131526 width=206)

任何想法如何对其进行优化?

1 个答案:

答案 0 :(得分:0)

我最终使用的解决方案是将GROUP BY分成多个:

首先,我创建一个临时表,其中包含要分组的东西的唯一ID。这只允许获得一部分结果(例如使用OFFSET和LIMIT),但是对于庞大的结果集,这些结果可能会非常慢(较大的偏移量意味着执行树仍会浏览第一个结果):

CREATE TEMP TABLE tempids AS SELECT ROW_NUMBER() OVER (ORDER BY theid), theid FROM (SELECT DISTINCT theid FROM sourcetable) sourcetable;

然后在WHILE循环中:

DO $$DECLARE
  r record;
  i INTEGER := 0;
  step INTEGER := 500000;
  size INTEGER := (SELECT COUNT(*) FROM tempids);
  BEGIN
  WHILE i <= size
      LOOP
        INSERT INTO target(theid, theresult)
        SELECT ... 
        WHERE tempids > i AND tempids < i + step
       GROUP BY tempids.theid;

这看起来像通常的编码,这不是很好的sql,但是可以用。