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.
Mit
set enable_nestloop = True
führt der Abfrageplaner Nested Loop Joining mit einer Gesamtlaufzeit von ca. 37 Sekunden aus: https://explain.depesz.com/s/59BRMit
set enable_nestloop = False
wird die Hash-Join-Methode verwendet und die Abfragezeit beträgt ca. 0,3 Sekunden: https://explain.depesz.com/s/PG8E
Ich habe es getan, VACUUM ANALYZE
bevor 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.
quelle
AND properties."TYPE_ID" IN (6);
und nicht= 6;
?Antworten:
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.
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 muss
nested_loop
Sie können einen oder zwei Indizes hinzufügen,
properties
um den seq-Scan möglicherweise vollständig zu überspringen oder die Rendite besser abzuschätzen.Alternativ können Sie das Eigenschaftenmaterial in einen CTE verschieben oder eine Unterauswahl treffen, mit
OFFSET 0
der ein Zaun erstellt wird.quelle