PostgreSQL 9.4には次のテーブルがあります。
_CREATE TABLE dpa(
id serial NOT NULL,
currency_id integer,
amount numeric(14,3),
date timestamp without time zone,
plat_id integer,
pl_id integer,
p_id integer,
CONSTRAINT dpa_pkey PRIMARY KEY (id),
)
_
と設定:
_work_mem = 128MB
table_size = 16 MB
_
そしてインデックス:
_CREATE INDEX idx1
ON dpa
USING btree
(plat_id, p_id, pl_id, currency_id, date DESC NULLS LAST, amount)
_
テーブルは約_242K
_行で構成されています。列に_NOT NULL
_制約はありませんが、実際には_NOT NULL
_です。
ここで、クエリのパフォーマンスを測定しています。
_SELECT plat_id, p_id, pl_id, player_account player_account
FROM(
SELECT plat_id, p_id, pl_id,
COALESCE(amount, 0) player_account,
ROW_NUMBER() OVER (PARTITION BY plat_id, p_id, pl_id, currency_id
ORDER BY date DESC NULLS LAST) rn
FROM dpa
) sub WHERE rn = 1;
_
分析された計画:
_Subquery Scan on sub (cost=0.42..25484.16 rows=1214 width=44) (actual time=0.044..296.810 rows=215274 loops=1)
Filter: (sub.rn = 1)
Rows Removed by Filter: 27556
-> WindowAgg (cost=0.42..22448.79 rows=242830 width=28) (actual time=0.043..255.690 rows=242830 loops=1)
-> Index Only Scan using idx1 on dpa (cost=0.42..16378.04 rows=242830 width=28) (actual time=0.037..91.576 rows=242830 loops=1)"
Heap Fetches: 242830
_
_SELECT DISTINCT ON(plat_id, p_id, pl_id, currency_id)
plat_id, p_id, pl_id, currency_id, amount
FROM dpa
ORDER BY plat_id, p_id, pl_id, currency_id, date DESC NULLS LAST
_
分析された計画:
_Unique (cost=0.42..18794.73 rows=82273 width=28) (actual time=0.017..128.277 rows=215274 loops=1)
-> Index Only Scan using idx1 on dpa (cost=0.42..16366.43 rows=242830 width=28) (actual time=0.016..72.110 rows=242830 loops=1)
Heap Fetches: 242830
_
ご覧のとおり、2番目のクエリは最初のクエリよりも高速です。しかし、PGAdmin
でこのクエリを実行すると、次の平均統計が得られました。
ROW_NUMBER()
(最初の)を使用したクエリ:_4999 ms
_
_DISTINCT ON
_(2番目)を使用したクエリ:_5654 ms
_
このような大きな結果セットに対するbandwith
/latency
オーバーヘッドが重要であることを理解しています。すべてのクエリは_215274
_行を生成します。
QUESTION:プランナーが2番目のケースですべての行を受信するのに最初のケースよりも時間がかかるのはなぜですか? 2番目の計画がより最適であることを示していますか?
表示されるタイミングはpgAdminによって指定されます(ただし、他のクライアントの場合もあります)。つまり、出力にgetおよびrenderに必要な時間を表示します。ご存じのとおり、データベースがデータを生成するために必要な時間(EXPLAIN ANALYZE
)、表示される違いはtransferおよび/またはレンダリングに由来する必要があります。たとえば、最初のクエリで表示される列が少なくなったことが原因である可能性があります。
転送中にどれだけの時間が消費されるかを知りたい場合は、アプリケーションからのクエリの実行の時間を計ることができます。データをフェッチするだけで、それをなんらかの方法で処理しない場合(レンダリングすることは言うまでもありません)、データの転送に必要な時間を適切に概算できます。データのフェッチに必要な時間をとり、データベースの(既知の)実行時間を差し引いてください。
このようにして、上記の数値と与えられた数値を比較することにより、pgAdminのレンダリング時間についても把握できます。