it-swarm.com.de

Postgres-Abfrageoptimierung (Erzwingen eines Index-Scans)

Unten ist meine Anfrage. Ich versuche, einen Index-Scan zu verwenden, aber es wird nur ein Sequenz-Scan durchgeführt.

Die metric_data-Tabelle hat übrigens 130 Millionen Zeilen. Die metrics-Tabelle hat ungefähr 2000 Zeilen.

metric_data Tabellenspalten:

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

Wie kann ich mit dieser Abfrage meinen PRIMARY KEY-Index verwenden?

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;

ERKLÄREN:

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[]))
25
Jeff

Zu Testzwecken können Sie die Verwendung des Index erzwingen, indem Sie sequentielle Prüfungen "deaktivieren" - am besten nur in Ihrer aktuellen Sitzung:

SET enable_seqscan = OFF;

Details im Handbuch hier. Ich habe "Deaktivieren" zitiert, da sequenzielle Tabellenscans nicht wirklich deaktiviert werden können. Aber jede andere verfügbare Option ist jetzt für Postgres vorzuziehen. Dies beweist, dass der mehrspaltige Index für (metric_id, t)can verwendet werden kann - nur nicht so effektiv wie ein Index für die führende Spalte.

Sie erhalten wahrscheinlich bessere Ergebnisse, wenn Sie die Reihenfolge der Spalten in Ihrem PRIMARY KEY (und dem Index, mit dem der Index hinter den Vorhängen implementiert wird) in (t, metric_id) ändern. Oder erstellen Sie einen additional -Index mit solchen umgekehrten Spalten.

Normalerweise müssen Sie keine besseren Abfragepläne durch manuelles Eingreifen erzwingen. Wenn die Einstellung enable_seqscan = OFF zu einem viel besseren Plan führt, ist möglicherweise etwas in Ihrer Datenbank nicht richtig. Betrachten Sie diese verwandte Antwort:

40

In diesem Fall kann der Index-Scan nicht erzwungen werden, da er dadurch nicht schneller wird.

Sie haben derzeit einen Index für metric_data (metric_id, t), der Server kann diesen Index jedoch nicht für Ihre Abfrage nutzen, da er nur nach metric_data.t (ohne metric_id) diskriminieren kann. Ein solcher Index ist jedoch nicht vorhanden. Der Server kann Unterfelder in zusammengesetzten Indizes verwenden, jedoch nur von Anfang an. Wenn Sie beispielsweise nach metric_id suchen, können Sie diesen Index verwenden. 

Wenn Sie einen anderen Index für metric_data (t) erstellen, verwendet Ihre Abfrage diesen Index und arbeitet viel schneller.

Sie sollten auch sicherstellen, dass Sie einen Index für metrics (id) haben.

1
mvp

Anscheinend fehlen Ihnen geeignete FK-Einschränkungen:

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)
)

und in Tabellenkennzahlen:

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

Überprüfen Sie auch, ob Ihre Statistiken ausreichen (und genau genug, da Sie 0,2% der Tabelle metrics_data auswählen möchten).

0
joop

Haben Sie versucht zu verwenden:

WHERE S.NAME = ANY (WERTE ('cpu'), ('mem')) Statt ARRAY

wie hier

0
Gabriel Bastos