PostgreSQL 9.2を使用すると、比較的大きなテーブル(2億を超える行)でクエリが遅くなるという問題が発生します。クレイジーなことは何もしていません。単に歴史的な価値を加えているだけです。以下は、クエリとクエリプランの出力です。
私のテーブルレイアウト:
Table "public.energy_energyentry"
Column | Type | Modifiers
-----------+--------------------------+-----------------------------------------------------------------
id | integer | not null default nextval('energy_energyentry_id_seq'::regclass)
prop_id | integer | not null
timestamp | timestamp with time zone | not null
value | double precision | not null
Indexes:
"energy_energyentry_pkey" PRIMARY KEY, btree (id)
"energy_energyentry_prop_id" btree (prop_id)
"energy_energyentry_prop_id_timestamp_idx" btree (prop_id, "timestamp")
Foreign-key constraints:
"energy_energyentry_prop_id_fkey" FOREIGN KEY (prop_id) REFERENCES gateway_peripheralproperty(id) DEFERRABLE INITIALLY DEFERRED
データは2012-01-01から現在までの範囲で、新しいデータが常に追加されています。 prop_id
外部キーには約2.2kの異なる値があり、均等に分散されています。
行の見積もりはそれほど遠くないことに気づきましたが、コストの見積もりは係数4倍大きくなっています。これはおそらく問題ではありませんが、それについて私ができることはありますか?
テーブルが常にメモリにあるわけではないので、ディスクアクセスが問題になる可能性があると思います。
EXPLAIN ANALYZE
SELECT SUM("value")
FROM "energy_energyentry"
WHERE
"prop_id"=82411
AND "timestamp">'2014-06-11'
AND "timestamp"<'2014-11-11'
;
Aggregate (cost=214481.45..214481.46 rows=1 width=8) (actual time=51504.814..51504.814 rows=1 loops=1) -> Index Scan using energy_energyentry_prop_id_timestamp_idx on energy_energyentry (cost=0.00..214434.08 rows=18947 width=8) (actual time=136.030..51488.321 rows=13578 loops=1) Index Cond: ((prop_id = 82411) AND ("timestamp" > '2014-06-11 00:00:00+00'::timestamp with time zone) AND ("timestamp" < '2014-11-11 00:00:00+00'::timestamp with time zone)) Total runtime: 51504.841 ms
これをより速くするための提案はありますか?
私も奇妙なことを何もしなかったと聞くだけでも大丈夫です。
テーブルはbigであり、テーブル全体に及ぶインデックスも同様です。仮定して:
timestamp = now()
付き)のみが入力されますCREATE INDEX ON energy_energyentry (prop_id, "timestamp", value)
WHERE "timestamp" >= '2014-01-01 0:0'; -- adapt to your needs
定期的に照会される時間範囲のみを含めてください。新しいエントリを使用すると、時間の経過とともに有効性が低下します。時々インデックスを再作成してください。 (クエリを調整する必要がある場合があります。)以下のリンクされた回答を参照してください。
最後の列の値は、これから インデックスのみのスキャン を取得するためにのみ含まれています。積極的なautovacuum設定は、可視性マップを最新の状態に保つことで役立つ場合があります @ jjanesはすでに述べたように 。
部分インデックスはRAM=に簡単に収まり、そこに長く留まるはずです。
次のように、このWHERE
条件をクエリに含めて、インデックスがクエリに適用可能であることをプランナーに理解させる必要がある場合があります。
SELECT sum(value) AS sum_value
FROM energy_energyentry
WHERE prop_id = 82411
AND "timestamp" > '2014-06-11 0:0'
AND "timestamp" < '2014-11-11 0:0'
AND "timestamp" >= '2014-01-01 0:0'; -- seems redundant, but may be needed
クエリは多数の行(rows=13578
)を合計しているため、インデックスのみのスキャンでも、これには時間がかかります。ただし、50秒近くになることはありません。中途半端なハードウェアでは1秒未満。
関連した (ただし、CLUSTER
とFILLFACTOR
は無視してください。これからインデックスのみのスキャンを実行できる場合は、どちらも無関係です):
脇:
現在現在に(prop_id, "timestamp")
のインデックスがあるため、(prop_id)
だけの追加のインデックスは、それは価値があります:
(prop_id、 "timestamp"、 "value")にインデックスを作成すると、インデックスのみのスキャンを使用して、テーブルにアクセスすることなく値を計算できます。これにより、多くのランダムディスクアクセスを節約できます。
最大限の利益を得るには、テーブルの掃除機を積極的に使用する必要があります。デフォルトのautovac設定は、インデックスのみのスキャンを効率的にサポートする必要のある挿入のみのテーブルに対して十分に積極的ではありません。