web-dev-qa-db-ja.com

Postgresクエリの最適化(インデックススキャンの強制)

以下は私のクエリです。インデックススキャンを使用するようにしようとしていますが、シーケンススキャンのみになります。

ちなみにmetric_dataテーブルには1億3000万行があります。 metricsテーブルには約2000行があります。

metric_dataテーブルの列:

  metric_id integer
, t timestamp
, d double precision
, PRIMARY KEY (metric_id, t)

このクエリを取得して、PRIMARY KEYインデックスを使用するにはどうすればよいですか?

SELECT
    S.metric,
    D.t,
    D.d
FROM metric_data D
INNER JOIN metrics S
    ON S.id = D.metric_id
WHERE S.NAME = ANY (ARRAY ['cpu', 'mem'])
  AND D.t BETWEEN '2012-02-05 00:00:00'::TIMESTAMP
              AND '2012-05-05 00:00:00'::TIMESTAMP;

説明:

Hash Join  (cost=271.30..3866384.25 rows=294973 width=25)
  Hash Cond: (d.metric_id = s.id)
  ->  Seq Scan on metric_data d  (cost=0.00..3753150.28 rows=29336784 width=20)
        Filter: ((t >= '2012-02-05 00:00:00'::timestamp without time zone)
             AND (t <= '2012-05-05 00:00:00'::timestamp without time zone))
  ->  Hash  (cost=270.44..270.44 rows=68 width=13)
        ->  Seq Scan on metrics s  (cost=0.00..270.44 rows=68 width=13)
              Filter: ((sym)::text = ANY ('{cpu,mem}'::text[]))
28
Jeff

テスト目的で、連続スキャンを「無効化」することにより、インデックスの使用を強制できます-現在のセッションでのみ最適です:

SET enable_seqscan = OFF;

マニュアルの詳細はこちら シーケンシャルテーブルスキャンを実際に無効にすることはできないため、「無効化」を引用しました。しかし、他の利用可能なオプションは現在、Postgresに適しています。これにより、(metric_id, t)canのマルチカラムインデックスが使用されることが証明されます-先行カラムのインデックスほど効果的ではありません。

おそらく、PRIMARY KEY(およびそれをカーテンの後ろに実装するために使用されるインデックス)の列の順序を(t, metric_id)に切り替えると、より良い結果が得られます。または、そのような逆の列を持つadditionalインデックスを作成します。

通常、手動での介入により、より良いクエリプランを強制する必要はありません。 enable_seqscan = OFFを設定することでmuchの改善された計画が得られる場合、データベースに何かが正しくない可能性があります。この関連する答えを検討してください:

44

この場合、インデックススキャンは強制的に高速化できません。

現在metric_data (metric_id, t)にインデックスがありますが、サーバーは_metric_data.t_のみ(_metric_id_なし)で識別できる必要があるため、クエリでこのインデックスを利用できませんが、そのようなインデックスはありません。サーバーは複合インデックスでサブフィールドを使用できますが、最初からのみ開始できます。たとえば、_metric_id_による検索では、このインデックスを使用できます。

metric_data (t)に別のインデックスを作成すると、クエリはそのインデックスを使用し、はるかに高速に動作します。

また、metrics (id)にインデックスがあることを確認する必要があります。

1
mvp

適切なFK制約が不足しているようです:

CREATE TABLE metric_data
( metric_id integer
, t timestamp
, d double precision
, PRIMARY KEY (metric_id, t)
, FOREIGN KEY metrics_xxx_fk (metric_id) REFERENCES metrics (id)
)

および表メトリックス:

CREATE TABLE metrics
( id INTEGER PRIMARY KEY
...
);

また、統計情報が十分かどうかを確認します(十分な粒度で、metrics_dataテーブルの0.2%を選択する予定です)。

0
joop

あなたが使用しようとしましたか:

WHERE S.NAME = ANY(VALUES( 'cpu')、( 'mem'))の代わりにARRAY

here のような

0
Gabriel Bastos