web-dev-qa-db-ja.com

時系列テーブルでのクエリの高速化。 (MAX-MIN)集計値を取得するのが遅い

質問

このクエリを改善して、以下に示すクエリの速度を+秒からミリ秒に上げる方法は? PostgreSQL:v 9.6.6を使用しています。

環境

データポイントの履歴データをテーブル_buildings.hispoint_に格納する時系列テーブル_buildings.point_があります。

データポイントの大規模なコレクションのさまざまな時間範囲(例:年初から)のMax(value) - Min(value) as aggregation_valueを集計する必要があります。

これは非常に遅いことが判明し、改善が必要です。

_buildings.hispoint_のテーブル構造((20,210,129 rows)

_CREATE TABLE buildings.hispoint (
    id int,
    value float,
    datetime timestamp,
    point_id …
    CONSTRAINT foo FOREIGN KEY (point_id)
    REFERENCES buildings.point (point_id),
    …
);
_

クエリ

_SELECT COUNT(datetime) AS id, 
MAX(value) - MIN(value) AS aggregation_value
FROM buildings_hispoint
WHERE point_id = 44 
AND buildings_hispoint.datetime BETWEEN '2018-01-01 00:00:00' AND '2018-05-02 09:18:14';
_

クエリプラン

_Aggregate  (cost=160967.11..160967.12 rows=1 width=16) (actual time=21713.720..21713.720 rows=1 loops=1)
  Buffers: shared hit=7817 read=66145 dirtied=1
  ->  Bitmap Heap Scan on buildings_hispoint  (cost=5705.82..159708.13 rows=167864 width=16) (actual time=161.733..21585.478 rows=19783 loops=1)
        Recheck Cond: (point_id = 44)
        Rows Removed by Index Recheck: 3474664
        Filter: ((datetime >= '2018-01-01 00:00:00+00'::timestamp with time zone) AND (datetime <= '2018-05-02 09:18:14+00'::timestamp with time zone))
        Rows Removed by Filter: 306305
        Heap Blocks: exact=46580 lossy=26488
        Buffers: shared hit=7817 read=66145 dirtied=1
        ->  Bitmap Index Scan on buildings_measurementdatapoint_ffb10c68  (cost=0.00..5663.85 rows=306589 width=0) (actual time=139.360..139.360 rows=326088 loops=1)
              Index Cond: (point_id = 44)
              Buffers: shared read=894
Planning time: 40.504 ms
Execution time: 21717.750 ms
_
4
ccostel

(point_id, datetime, value)のインデックスは、インデックスシークを実行し、インデックスの関連部分のみを読み取り、value列のすべての値を(インデックスから)利用できるため、クエリを高速化する可能性がありますMINおよびMAXを計算します。

(A)(point_id)または(B)(point_id, datetime)のインデックスは、(A)日時範囲および(AとB)value列の値を読み取る。

7
ypercubeᵀᴹ

ランタイムでフロートにキャストしている、

MAX(value::float) - MIN(value::float) AS aggregation_value

その効果が必要な場合は、valueタイプを浮動小数点に変更するだけです。

ALTER TABLE buildings.hispoint
  ALTER COLUMN value
  SET DATA TYPE TO float;

また、1行しか返さない場合のORDER BY 1 ascの意味は何ですか?

4
Evan Carroll