web-dev-qa-db-ja.com

集約関数のPostgresインデックス

クエリ:

SELECT
  "places_place"."id"
FROM "places_place"
  LEFT OUTER JOIN "units_unit" ON ("places_place"."id" = "units_unit"."place_id")
GROUP BY "places_place"."id"
HAVING SUM("units_unit"."quantity") >= 123

インデックス試行:

CREATE INDEX units_quantity_sum ON units_unit (SUM("units_unit"."quantity"));
-- ERROR:  aggregate functions are not allowed in index expressions

基本的には、結果をテーブルの別の列に格納せずに、SUMの結果にインデックスを付ける必要があります。これを行うにはどうすればインデックスを作成できますか(またはこのクエリを最適化するためのより良い方法があります)?

EXPLAIN ANALYZEに10,000行を含むクエリのplaces_placeおよび25,000 in units_unit

HashAggregate  (cost=2057.31..2157.33 rows=10002 width=4) (actual time=38.121..41.174 rows=7727 loops=1)
  Group Key: places_place.id
  Filter: (sum(units_unit.quantity) >= 5)
  Rows Removed by Filter: 2275
  ->  Hash Right Join  (cost=594.04..1932.22 rows=25018 width=6) (actual time=6.383..28.578 rows=26727 loops=1)
        Hash Cond: (units_unit.place_id = places_place.id)
        ->  Seq Scan on units_unit  (cost=0.00..994.18 rows=25018 width=6) (actual time=0.003..7.279 rows=25018 loops=1)
        ->  Hash  (cost=469.02..469.02 rows=10002 width=4) (actual time=6.311..6.311 rows=10002 loops=1)
              Buckets: 16384  Batches: 1  Memory Usage: 480kB
              ->  Seq Scan on places_place  (cost=0.00..469.02 rows=10002 width=4) (actual time=0.007..3.560 rows=10002 loops=1)
Planning time: 0.584 ms
Execution time: 42.643 ms
3
dvtan

2つの簡単なオプションがあります

  1. _MATERIALIZED VIEW_を使用できます
  2. 別のテーブルを挿入するTRIGGERを使用することもできます。

これらの両方で、SUM()をキャッシュできます。常に最新の変更が必要でない限り、_MATERIALIZED VIEW_を使用します。

PostgreSQL 9.6でそのルートを進む前に、並列seqスキャンと集約を有効にすると、パフォーマンスが向上します。実際、これは 理想的な使用例 です。あなたがジャストこれを速くする必要がある場合は、設定を試してください _max_parallel_workers_per_gather_

3
Evan Carroll