Mam problem z planowaniem zapytań PostgreSQL 9.6. Moje zapytanie wygląda następująco:
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)
Mam włączone zabezpieczenia na poziomie wiersza dla wyżej używanych tabel.
za pomocą
set enable_nestloop = True
, narzędzie do planowania zapytań uruchamia łączenie zagnieżdżonej pętli z łącznym czasem działania około 37 sekund: https://explain.depesz.com/s/59BRz
set enable_nestloop = False
, używana jest metoda łączenia Hash, a czas zapytania wynosi około 0,3 s: https://explain.depesz.com/s/PG8E
Zrobiłem to VACUUM ANALYZE
przed uruchomieniem zapytań, ale to nie pomogło.
Wiem, że nie jest to dobra praktyka set enable_nestloop = False
i inne podobne opcje dla planisty. Ale jak mogę „przekonać” planistę do korzystania z połączeń mieszających bez wyłączania zagnieżdżonych pętli?
Przepisanie zapytania jest opcją.
Jeśli uruchomię to samo zapytanie w roli, która omija RLS, jest ono wykonywane bardzo szybko. Polityka bezpieczeństwa na poziomie wiersza wygląda następująco:
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
);
Wszelkie pomysły i sugestie będą mile widziane.
źródło
AND properties."TYPE_ID" IN (6);
a nie= 6;
?Odpowiedzi:
To, co się tutaj dzieje, to zagnieżdżona pętla z jednej strony. Zagnieżdżone pętle działają naprawdę dobrze, gdy jedna strona jest bardzo mała, na przykład zwracając jeden rząd. W zapytaniu planista grzebiąc tutaj, szacuje, że funkcja łączenia mieszającego zwróci tylko jeden wiersz. Zamiast tego funkcja Hash Join (property_id = id) zwraca 1338 wierszy. Wymusza to uruchomienie 1338 pętli po drugiej stronie zagnieżdżonej pętli, która ma już 3444 wiersze. To bardzo dużo, gdy oczekujesz tylko jednego (który nie jest nawet „pętlą”). W każdym razie ..
Dalsze badanie, gdy schodzimy w dół, pokazuje, że łączenie Hash jest naprawdę zniekształcone przez szacunki wynikające z tego
PostgreSQL oczekuje, że zwróci jeden wiersz. Ale tak nie jest. I to naprawdę twój problem. Oto niektóre opcje, które nie wymagają wyjmowania młota i wyłączania
nested_loop
Możesz dodać indeks lub dwa, aby
properties
pomóc potencjalnie całkowicie pominąć skanowanie seq lub lepiej oszacować zwrot.Alternatywnie możesz przenieść właściwości właściwości do CTE lub podselekcji, z
OFFSET 0
którą tworzy ogrodzenie.źródło