Saya mengalami masalah dengan perencanaan kueri PostgreSQL 9.6. Kueri saya terlihat seperti ini:
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)
Saya mengaktifkan Row-Level Security untuk tabel yang digunakan di atas.
dengan
set enable_nestloop = True
, perencana kueri menjalankan Nested Loop bergabung dengan total waktu berjalan sekitar 37 detik: https://explain.depesz.com/s/59BRdengan
set enable_nestloop = False
, metode Hash Join digunakan dan waktu kueri sekitar 0,3 detik: https://explain.depesz.com/s/PG8E
Saya lakukan VACUUM ANALYZE
sebelum menjalankan kueri, tetapi itu tidak membantu.
Saya tahu bahwa ini bukan praktik yang baik set enable_nestloop = False
, dan opsi serupa lainnya untuk perencana. Tetapi bagaimana saya bisa "meyakinkan" perencana untuk menggunakan hash bergabung tanpa menonaktifkan loop bersarang?
Menulis ulang kueri adalah opsi.
Jika saya menjalankan kueri yang sama di bawah peran yang melewati RLS, maka itu dijalankan sangat cepat. Kebijakan keamanan tingkat baris terlihat seperti ini:
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
);
Setiap ide atau saran akan sangat dihargai.
sumber
AND properties."TYPE_ID" IN (6);
dan tidak= 6;
?Jawaban:
Apa yang terjadi di sini adalah Nested Loop jauh di satu sisi. Nested Loops bekerja sangat baik ketika satu sisi sangat kecil, seperti mengembalikan satu baris. Dalam kueri Anda, perencana meraba-raba di sini dan memperkirakan bahwa Hash Join akan mengembalikan hanya satu baris. Alih-alih, Hash Join (property_id = id) mengembalikan 1.338 baris. Ini memaksa 1.338 loop untuk berjalan di sisi lain Nested Loop yang sudah memiliki 3.444 baris. Itu banyak hal ketika Anda hanya mengharapkan satu (yang bahkan tidak banyak "loop"). Pokoknya ..
Pemeriksaan lebih lanjut saat kami bergerak turun menunjukkan bahwa Hash Join benar-benar borked oleh estimasi yang timbul dari ini,
PostgreSQL mengharapkan itu mengembalikan satu baris. Tapi ternyata tidak. Dan, itu benar-benar masalah Anda. Jadi beberapa opsi di sini, yang tidak melibatkan mengeluarkan palu godam dan melumpuhkan
nested_loop
Anda dapat menambahkan satu atau dua indeks
properties
untuk membantunya berpotensi melewati pemindaian seq sepenuhnya, atau memperkirakan pengembalian lebih baik.Atau, Anda dapat memindahkan properti ke CTE atau subselect
OFFSET 0
yang membuat pagar.sumber