it-swarm.com.de

Hilft das Abdecken von Indizes in PostgreSQL dabei, Spalten zu verbinden?

Ich habe eine ganze Reihe von Tabellen, die vage so aussehen:

CREATE TABLE table1(id INTEGER PRIMARY KEY, t1c1 INTEGER, t1c2 INTEGER);
CREATE TABLE table2(id INTEGER PRIMARY KEY, t1 INTEGER REFERENCES table1(id), t2c1 INTEGER);

Und ich mache eine ganze Reihe von Joins, bei denen ich versuche, nach der verbundenen Tabelle zu filtern, um Dinge aus der ersten Tabelle zu erhalten, wie folgt:

SELECT t1c1
FROM table1
JOIN table2 ON table2.t1 = table1.id
WHERE t2c1 = 42;

Wenn ich Indizes für eine Tabelle schreibe, schaue ich mir die Spalten an, die in der WHERE-Klausel verwendet werden, und erstelle Indizes, um sie zu erfüllen. Für diese Abfrage würde ich also einen Index wie diesen schreiben:

CREATE INDEX ON table2 (t2c1);

Und dieser Index kann zumindest in dieser Abfrage verwendet werden.

Meine Frage ist, wenn ich einen Index wie diesen schreibe:

CREATE INDEX ON table2 (t2c1, t1);

Wird der Index als Deckungsindex verwendet, um dem JOIN bei der obigen Abfrage zu helfen? Sollte ich meine Strategie zum Schreiben von Indizes ändern, um Fremdschlüsselspalten abzudecken?

8
ldrg

Wird der Index als Deckungsindex verwendet, um dem JOIN bei der obigen Abfrage zu helfen?

Es hängt davon ab, ob. Postgres hat "Nur-Index" -Scans als Indexzugriffsmethode , es gibt per se keine "Deckungsindizes" - bis zu Postgres 10.

Beginnend mit Postgres 11 True Covering-Indizes mit INCLUDE Spalten sind verfügbar. Blogeintrag von Michael Paquier zur Einführung der Funktion:

Verwandte Antwort mit Codebeispiel:

Der Index CREATE INDEX ON table2 (t2c1, t1); ist jedoch für die von Ihnen demonstrierte Abfrage absolut sinnvoll. Es kann für einen Nur-Index-Scan verwendet werden, wenn zusätzliche Voraussetzungen erfüllt sind, oder es kann in einem Bitmap-Index-Scan oder einem einfachen Index-Scan verwendet werden. Verbunden:

JOIN Bedingungen und WHERE Bedingungen sind fast in Postgres völlig gleichwertig. Sie können Indizes sicherlich auf die gleiche Weise verwenden. Sie können Ihre Abfrage neu schreiben

SELECT t1c1
FROM   table1
JOIN   table2 ON table2.t1 = table1.id
WHERE  t2c1 = 42;

Mit diesem Äquivalent:

SELECT t1c1
FROM   table1 CROSS JOIN table2
WHERE  table2.t1 = table1.id
AND    table2.t2c1 = 42;

Die erste Form ist jedoch offensichtlich vorzuziehen. Einfacher zu lesen.

Warum "fast" gleichwertig?

15

Wird der Index als Deckungsindex verwendet, um dem JOIN bei der obigen Abfrage zu helfen? Sollte ich meine Strategie zum Schreiben von Indizes ändern, um Fremdschlüsselspalten abzudecken?

In der obigen Abfrage nicht wahrscheinlich. Dies ist ein täuschendes komplexes Problem mit den Ergebnissen, die auf den Schätzungen und der Selektivität der beiden Bedingungen basieren.

  • table2.t1 = table1.id
  • t2c1 = 42

Im Wesentlichen möchten Sie beide Umgebungen (Zeilenanzahl) auslösen, damit beide Bedingungen mehr oder weniger selektiv sind. Und wenn Sie eine verschachtelte Schleife erhalten, möchten Sie die Rohmenge erhöhen, bis dies nicht mehr die praktikabelste Join-Methode ist.

CREATE TABLE table1(
   id INTEGER PRIMARY KEY,
   t1c1 INTEGER,
   t1c2 INTEGER
);
INSERT INTO table1(id, t1c1, t1c2)
  SELECT x,x,x FROM generate_series(1,1000)
  AS gs(x);

CREATE TABLE table2(
  id INTEGER PRIMARY KEY,
  t1 INTEGER REFERENCES table1(id),
  t2c1 INTEGER
);
INSERT INTO table2(id, t1, t2c1)
SELECT x,1+x%1000,x%50 FROM generate_series(1,1e6)
  AS gs(x);

EXPLAIN ANALYZE
  SELECT t1c1
  FROM table1
  JOIN table2 ON table2.t1 = table1.id
  WHERE t2c1 = 42;

Überprüfen Sie nun den Plan.

Erstellen Sie nun den zusammengesetzten Index.

CREATE INDEX ON table2 (t2c1, t1);
VACUUM FULL ANALYZE table1;
VACUUM FULL ANALYZE table2;

Und überprüfen Sie den Plan noch einmal,

EXPLAIN ANALYZE
  SELECT t1c1
  FROM table1
  JOIN table2 ON table2.t1 = table1.id
  WHERE t2c1 = 42;

Sie können die Schlüssel und dergleichen ablegen, um herauszufinden, welche Form sie bevorzugen

CREATE INDEX ON table2 (t1, t2c1);

oder

CREATE INDEX ON table2 (t2c1, t1);

Obwohl dies eine Menge Arbeit ist, schlage ich vor, mit zu beginnen

CREATE INDEX ON table2 (t1);
CREATE INDEX ON table2 (t2c1);

Und nur dann optimieren, wenn das nicht ausreicht.

Sie können auch bestimmte Planeroptionen deaktivieren, um festzustellen, ob ein anderer Plan wirklich schneller oder langsamer ist, und dann versuchen, dies zu beheben, aber das kann auch viel Arbeit bedeuten.

3
Evan Carroll