web-dev-qa-db-ja.com

非常に遅いpostgresql集計

編集:同じデータでテストするためのDockerイメージ(難読化)

$ docker run --rm --name pg -d homer5439/pgagg
$ docker exec -ti pg bash
# createdb -U postgres test; zcat /tmp/corr.sql.gz | psql -U postgres test
# psql -U postgres test

以下の例を実行できます。


Postgresql 12.2で次のクエリが30秒以上かかるのはなぜでしょうか。

SELECT
    contract_id,
    array_agg(corr) AS corr
  FROM
    corr
  GROUP BY contract_id;

詳細:corrテーブルには約150000レコードがあります。各レコードの構造は次のとおりです。

gse=# \d corr ;
                                         Table "public.corr"
    Column   |  Type   | Collation | Nullable |                             Default                             
-------------+---------+-----------+----------+-----------------------------------------------------------------
 corr_id     | integer |           | not null | nextval('corr_corr_id_seq'::regclass)
 contract_id | integer |           |          | 
 start_date  | date    |           |          | 
 corr_type   | text    |           |          | 
 descr       | text    |           |          | 
 credit      | numeric |           |          | 
 detail      | text    |           |          | 
Indexes:
    "corr_pkey" PRIMARY KEY, btree (corr_id)
    "corr_contract_id_idx" btree (contract_id)

detailフィールドには、最大2/3 MBの長さのテキストが含まれます(レコードの約10%にその詳細が含まれ、その他のレコードには(〜10-20)キロバイトがあります)。個別のcontract_id値の数は現在2317です。

このサイトで見つかった他の提案に従って、目立った変更なしにwork_memの値を最大10GBに変更してみました。

クエリプランは次のとおりです。

                                                                 QUERY PLAN                                                   
---------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate  (cost=9883.29..9911.57 rows=2263 width=36) (actual time=1184.971..1357.309 rows=2317 loops=1)
   Output: contract_id, array_agg(corr.*)
   Group Key: corr.contract_id
   Buffers: shared hit=78012 read=49899
   ->  Seq Scan on public.corr (cost=0.00..9320.19 rows=112619 width=571 (actual time=0.057..959.359 rows=112619 loops=1)
         Output: contract_id, corr.*
         Buffers: shared hit=78012 read=49899
Planning Time: 0.131 ms
Execution Time: 1357.747 ms
2
homer5439

「スタンドアロン」を実行する場合、「psql」で実行することを意味しますが、EXPLAIN ANALYZEを使用しないと、「psql」は結果セット全体をメモリに読み取り、そのセットを調べて、それぞれの最長エントリの長さを決定します。列をその長さにフォーマットできるようにします。 2317行の場合30秒は期待できませんが、遅くなる可能性があります。

「corr」テーブルに「corr」列がないことを除いて、集計しているのは行レコード全体であり、すでに言ったように、非常に幅が広​​くなる可能性があります。そのため、psqlで大量のデータを投入しているため、処理に時間がかかり、スワップが発生する可能性があります。

1
jjanes