Unerwünschte Nestschleife vs. Hash Join in PostgreSQL 9.6


13

Ich habe Probleme mit der Abfrageplanung für PostgreSQL 9.6. Meine Anfrage sieht folgendermaßen aus:

SET role plain_user;

SELECT properties.*
FROM properties
JOIN entries_properties
  ON properties.id = entries_properties.property_id
JOIN structures
  ON structures.id = entries_properties.entry_id 
WHERE structures."STRUKTURBERICHT" != ''
  AND properties."COMPOSITION" LIKE 'Mo%'
  AND (
    properties."NAME" LIKE '%VASP-ase-preopt%'
    OR properties."CALCULATOR_ID" IN (7,22,25)
  )
AND properties."TYPE_ID" IN (6)

Ich habe die Sicherheit auf Zeilenebene für die oben verwendeten Tabellen aktiviert.

Ich habe es getan, VACUUM ANALYZEbevor ich die Abfragen ausgeführt habe, aber es hat nicht geholfen.

Ich weiß, dass es keine gute Praxis ist set enable_nestloop = False, und andere ähnliche Optionen für den Planer. Aber wie könnte ich den Planer "überzeugen", Hash-Joins zu verwenden, ohne verschachtelte Schleifen zu deaktivieren?

Das Umschreiben der Abfrage ist eine Option.

Wenn ich dieselbe Abfrage unter einer Rolle ausführe, die RLS umgeht, wird sie sehr schnell ausgeführt. Die Sicherheitsrichtlinie auf Zeilenebene sieht folgendermaßen aus:

CREATE POLICY properties_select
ON properties
FOR SELECT
USING (
  (
    properties.ouid = get_current_user_id()
    AND properties.ur
  )
  OR (
    properties.ogid in (select get_current_groups_id())
    AND properties.gr
  )
  OR properties.ar
);

Irgendwelche Ideen oder Vorschläge würden sehr geschätzt.


Nur ein bisschen verwirrt: Warum haben AND properties."TYPE_ID" IN (6);und nicht = 6;?
Vérace

2
@ Vérace while = wird häufiger verwendet, beide werden auf die gleiche Weise geplant. Ich gehe davon aus, dass er mit mehr als einem Wert spielt oder ein ORM ein bisschen faul ist.
Evan Carroll

Antworten:


16

Was hier passiert, ist, dass die verschachtelte Schleife auf einer Seite weit entfernt ist. Verschachtelte Schleifen funktionieren sehr gut, wenn eine Seite sehr klein ist, z. B. wenn eine Zeile zurückgegeben wird. In Ihrer Abfrage fummelt der Planer hier herum und schätzt, dass ein Hash-Join nur eine Zeile zurückgibt. Stattdessen gibt dieser Hash-Join (property_id = id) 1.338 Zeilen zurück. Dies zwingt 1.338 Schleifen, auf der anderen Seite der verschachtelten Schleife zu laufen, die bereits 3.444 Zeilen hat. Das ist eine Menge, wenn Sie nur eine erwarten (was nicht einmal eine große "Schleife" ist). Wie auch immer ..

Eine weitere Untersuchung, während wir uns nach unten bewegen, zeigt, dass der Hash-Join durch die daraus resultierenden Schätzungen wirklich in Mitleidenschaft gezogen wird.

Filter: (((properties."COMPOSITION")::text ~~ 'Mo%'::text) AND (((properties."NAME")::text ~~ '%VASP-ase-preopt%'::text) OR (properties."CALCULATOR_ID" = ANY ('{7,22,25}'::integer[]))))

PostgreSQL erwartet, dass eine Zeile zurückgegeben wird. Aber das tut es nicht. Und das ist wirklich dein Problem. Einige Optionen hier, bei denen kein Vorschlaghammer herausgenommen und deaktiviert werden mussnested_loop

  • Sie können einen oder zwei Indizes hinzufügen, propertiesum den seq-Scan möglicherweise vollständig zu überspringen oder die Rendite besser abzuschätzen.

    CREATE INDEX ON properties USING ( "TYPE_ID", "CALCULATOR_ID" );
    -- the gist_trgm_ops may or may not be needed depending on selectivity of above.
    CREATE INDEX ON properties USING GIST (
      "COMPOSITION" gist_trgm_ops,
      "NAME"        gist_trgm_ops
    );
    ANALYZE properties;
  • Alternativ können Sie das Eigenschaftenmaterial in einen CTE verschieben oder eine Unterauswahl treffen, mit OFFSET 0der ein Zaun erstellt wird.

    WITH t AS (
      SELECT *
      FROM properties.
      WHERE "COMPOSITION" LIKE 'Mo%'
      AND (
        "NAME" LIKE '%VASP-ase-preopt%'
        OR "CALCULATOR_ID" IN (7,22,25)
      )
      AND "TYPE_ID" IN (6)
    )
    SELECT * FROM structures
    JOIN t ON (
      structures.id = entries_properties.entry_id
    )
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.