45

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

ちなみに、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[]))
4

4 に答える 4

81

テスト目的で、シーケンシャル スキャンを「無効にする」ことでインデックスの使用を強制できます。現在のセッションでのみ最適です。

SET enable_seqscan = OFF;

これを本稼働サーバーでは使用しないでください。マニュアルの詳細はこちら。

シーケンシャル テーブル スキャンを実際に無効にすることはできないため、「無効にする」と引用しました。しかし、現在 Postgres には他の利用可能なオプションが望ましいです。(metric_id, t) これは、複数列のインデックスを使用できることを証明しますが、先頭の列のインデックスほど効果的ではありません。

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

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

于 2013-01-28T04:50:36.263 に答える
2

この場合、インデックススキャンは高速化されないため、強制することはできません。

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

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

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

于 2013-01-28T04:00:47.517 に答える
0

使用しようとしましたか:

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

ここのように

于 2016-03-21T17:48:07.450 に答える
0

適切な 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 % を選択するつもりなので、十分に細かく設定されているかどうかも確認してください)。

于 2013-01-28T10:52:38.493 に答える