3

フィールドでBETWEEN句を使用する PostgreSQL クエリを最適化するのに助けが必要です。timestamp

私は2つのテーブルを持っています:

ONE(int id_one(PK), datetime cut_time, int f1 . . .) 

約 3394 行を含む

TWO(int id_two(PK), int id_one(FK), int f2 . . .) 

約4000000行を含む

id_onePKとid_twoの両方、FKid_oneとに btree インデックスがありますcut_time

次のようなクエリを実行したい:

select o.id_one, Date(o.cut_time), o.f1, t.f2 
from one o
inner join two t ON (o.id_one = t.id_one)
where o.cut_time between '2013-01-01' and '2013-01-31';

このクエリは、約 7 秒で約 1.700.000 行を取得します。

Explain Analyse レポートの下に、次のレポートが表示されます。

"Merge Join  (cost=20000000003.53..20000197562.38 rows=1680916 width=24) (actual time=0.017..741.718 rows=1692345 loops=1)"
"  Merge Cond: (c.coilid = hf.coilid)"
"  ->  Index Scan using pk_coils on coils c  (cost=10000000000.00..10000000382.13 rows=1420 width=16) (actual time=0.008..4.539 rows=1404 loops=1)"
"        Filter: ((cut_time >= '2013-01-01 00:00:00'::timestamp without time zone) AND (cut_time <= '2013-01-31 00:00:00'::timestamp without time zone))"
"        Rows Removed by Filter: 1990"
"  ->  Index Scan using idx_fk_lf_data on hf_data hf  (cost=10000000000.00..10000166145.90 rows=4017625 width=16) (actual time=0.003..392.535 rows=1963386 loops=1)"
"Total runtime: 768.473 ms"

タイムスタンプ列のインデックスは使用されません。このクエリを最適化する方法は?

4

2 に答える 2

6

適切な DDL スクリプト

質問で使用している表記の種類がわかりません。Postgres 構文ではありません。適切なセットアップは次のようになります:
SQL Fiddle.

このフィドルの詳細については、さらに下を参照してください。列の
データ型を想定しています。timestampdatetime

不適切なクエリ

BETWEEN列を持つプリンシパルでは、ほとんどの場合間違っtimestampています。この関連する回答の詳細:

あなたのクエリで:

SELECT o.one_id, date(o.cut_time), o.f1, t.f2 
FROM   one o
JOIN   two t USING (one_id)
WHERE  o.cut_time BETWEEN '2013-01-01' AND '2013-01-31';

... 文字列定数 '2013-01-01' および '2013-01-31' は、タイムスタンプ '2013-01-01 00:00' および '2013-01-31 00:00' に強制されます。これは 1 月 31 日のほとんどを除外します
代わりに「2013-02-01」を上枠として使用すると、「2013-02-01 00:00」が含まれます。まだ間違っています。

「2013 年 1 月」のすべてのタイムスタンプを取得するには、次のようにする必要があります

SELECT o.one_id, date(o.cut_time), o.f1, t.f2 
FROM   one o
JOIN   two t USING (one_id)
WHERE  o.cut_time >= '2013-01-01'
AND    o.cut_time <  '2013-02-01';

上の境界線を除外します。

クエリを最適化する

@Clodoaldoは、パフォーマンスの主な障害について既に言及しています。1.7 ミリオの行を取得するのはおそらく無意味です。結果を取得する前に集計します。

テーブルtwoは非常に大きいため、重要なのは行です。そこから取得する必要があります。テーブルの大部分 ( ~ 5% を超える) を取得する限り、テーブルをすぐに順番にスキャンする方が高速であるため、単純なインデックスはtwo.one_id使用されません。

テーブルの統計情報が古くなっているか、コスト定数やその他のパラメーター (明らかに持っているものです。以下を参照) を台無しにして、とにかく Postgres にインデックスを使用させています。

インデックスの唯一の可能性は、 PostgreSQL 9.2twoカバリング インデックスです。しかし、バージョン番号を開示することを怠りました。

CREATE INDEX two_one_id_f2 on two(one_id, f2);

このようにして、いくつかの前提条件が満たされている場合、Postgres はインデックスから直接読み取ることができます。少し速いかもしれませんが、それほどではありません。テストしませんでした。

EXPLAIN出力の奇妙な数値

あなたの奇妙な数字についてはEXPLAIN ANALYZE。このSQL Fiddleで説明する必要があります。

これらのデバッグ設定があったようです:

SET enable_seqscan = off;
SET enable_indexscan = off;
SET enable_bitmapscan = off;

onデバッグを除いて、それらはすべて である必要があります。パフォーマンスが低下します。確認する:

SELECT * FROM pg_settings WHERE name ~~ 'enable%'
于 2013-04-16T22:23:11.727 に答える