Saya mendapat 2 set poin dalam 2 tabel terpisah. Table_a mendapat 100rb poin dan table_b mendapat 300rb poin. Saya mencoba menemukan titik terdekat dalam kaitannya menemukan saya titik dari table_b yang berjarak 50 meter dari tabla_a. Setelah itu hitung kolom jatuh, kelompokkan dengan table_a a_id kolom dan kembalikan nilai tertinggi.
Saya menulis pertanyaan berikut yang memenuhi criteira ini
SELECT DISTINCT ON (a_id) *
FROM (
SELECT
table_b.b_id,
table_b.height - st_3ddistance(table_b.geom, table_a.geom) fall,
table_b.geom,
table_a.a_id
FROM table_a
INNER JOIN table_b ON _st_3ddwithin(table_a.geom, table_b.geom, 50)) a
WHERE fall >= 0
ORDER BY a_id, fall DESC;
Saya menambahkan indeks geometri 3d:
CREATE INDEX table_a_geom ON table_a USING GIST (geom gist_geometry_ops_nd);
CREATE INDEX table_b_geom ON table_b USING GIST (geom gist_geometry_ops_nd);
Namun masalah saya adalah bahwa saya tidak dapat membuat permintaan untuk menggunakannya. Query planer terus memilih pemindaian urutan yang lambat. Saya menjalankan beberapa pengujian mengubah _st_3ddwithin dengan st_3ddwithin , <<->> <50 , membuat buffer 50 m dan memotong , st_3ddistance <50 tetapi setiap perencana memilih pemindaian urutan. Apakah ada cara untuk menggunakan indeks dengan kinerja lebih tinggi atau mengubah kueri untuk menggunakan indeks?
Paket kueri saya:
Unique (cost=10462593.70..10473018.43 rows=1 width=144)
-> Sort (cost=10462593.70..10467806.06 rows=2084945 width=144)
Sort Key: table_a.nmbayuid, ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom))) DESC
-> Nested Loop (cost=0.00..10243762.28 rows=2084945 width=144)
Join Filter: (_st_dwithin(table_a.geom, table_b.geomgr, '50'::double precision) AND ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom)) >= '0'::double precision))
-> Seq Scan on table_b (cost=0.00..1459.47 rows=47147 width=96)
-> Materialize (cost=0.00..10.97 rows=398 width=56)
-> Seq Scan on table_a (cost=0.00..8.98 rows=398 width=56)
sumber
_ST
fungsi internal yang dipanggil oleh PostGIS setelah difilter dengan indeks. Jika Anda memanggil mereka secara langsung, indeks tidak akan digunakan.Jawaban:
Pertama, seperti yang telah dicatat dalam komentar, garis bawah yang memimpin sebelum fungsi ST, yaitu, _ST_3DWithin akan menyebabkan indeks tidak digunakan. Saya tidak dapat menemukan penyebutan baru-baru ini, tetapi dalam dokumen lama jika Anda mencari, misalnya, _ST_Intersects menyatakan:
EDIT: Sebagaimana diklarifikasi oleh @dbaston dalam komentar, fungsi dengan garis bawah utama adalah fungsi internal yang tidak menggunakan indeks saat dipanggil dan ini terus menjadi kasus (meskipun sulit ditemukan di dokumen).
Kueri Anda mungkin dapat memanfaatkan sintaks LATERAL JOIN, yang cocok untuk masalah k tetangga terdekat (kNN) seperti ini.
Ini memungkinkan Anda untuk menemukan geometri k terdekat dari tabel a (dalam hal ini 1, karena LIMIT 1) ke tabel b, diurutkan berdasarkan jarak 3D di antara mereka. Ini ditulis menggunakan LEFT JOIN, karena dapat dibayangkan bahwa mungkin ada beberapa geometri dalam tabel a yang tidak berada dalam jarak 50 meter dari tabel b.
Kueri lateral memungkinkan Anda untuk merujuk kolom dari klausa FROM sebelumnya, yang membuatnya lebih kuat daripada sub kueri standar, lihat dokumen .
Saya tidak dapat menguji ini terhadap data Anda, tetapi ketika saya telah menjalankan pertanyaan serupa, pernyataan EXPLAIN menunjukkan penggunaan indeks yang tepat.
sumber
Tautan ini ke dokumentasi PostGIS merekomendasikan langkah-langkah berikut untuk memastikan indeks dan perencana kueri dioptimalkan:
Pastikan statistik dikumpulkan tentang jumlah dan distribusi nilai dalam tabel, untuk memberikan informasi yang lebih baik kepada perencana kueri untuk membuat keputusan seputar penggunaan indeks. VACUUM ANALYZE akan menghitung keduanya.
Jika menyedot debu tidak membantu, Anda dapat sementara memaksa perencana untuk menggunakan informasi indeks dengan menggunakan set enable_seqscan untuk dimatikan; perintah. Dengan cara ini Anda dapat memeriksa apakah perencana sama sekali mampu menghasilkan rencana kueri dipercepat indeks untuk permintaan Anda. Anda hanya harus menggunakan perintah ini hanya untuk debug: secara umum, perencana tahu lebih baik daripada yang Anda lakukan saat menggunakan indeks. Setelah menjalankan kueri, jangan lupa untuk mengaktifkan ENABLE_SEQSCAN kembali, sehingga kueri lain akan menggunakan perencana seperti biasa.
Jika atur enable_seqscan ke off; membantu permintaan Anda untuk menjalankan, Postgres Anda kemungkinan tidak disesuaikan untuk perangkat keras Anda. Jika Anda menemukan perencana yang salah tentang biaya scan indeks berurutan vs coba kurangi nilai random_page_cost di postgresql.conf atau gunakan set random_page_cost ke 1.1 ;. Nilai default untuk parameter adalah 4, coba atur ke 1 (pada SSD) atau 2 (pada disk magnetik cepat). Penurunan nilai membuat perencana lebih cenderung menggunakan pemindaian Indeks.
Jika atur enable_seqscan ke off; tidak membantu permintaan Anda, mungkin saja Anda menggunakan konstruksi Postgres belum dapat diurai. Subquery dengan inline select adalah salah satu contoh - Anda perlu menulis ulangnya sehingga form planner dapat mengoptimalkan, katakanlah, LATERAL JOIN.
Jadi, pertama-tama coba langkah 1-3 sebelum menulis ulang kueri Anda untuk menggunakan indeks. Jika itu tidak berhasil, Anda bisa mencoba memodifikasi kueri.
Saya percaya (dengan kemampuan terbaik saya untuk menyiapkan SQL tanpa menjalankan kode) bahwa kueri di bawah ini akan mengembalikan hasil yang identik dengan Anda, tetapi tidak tahu apakah itu akan lebih efisien.
sumber
Jika Anda menggunakan Postgres 10 (atau lebih baru), saya akan sangat menyarankan memuat data Anda dalam tabel Paralel.
Anda mungkin perlu menghabiskan waktu menyetelnya (partisi data, dan jumlah pekerja), tapi saya pikir sepadan dengan usaha. Secara teoritis, KNN sangat paralel, mencapai kompleksitas waktu yang konstan, bahkan O (1) jika jumlah pekerja sama dengan jumlah elemen di mana operasi KNN akan dihitung.
Beberapa referensi praktis tentang memuat data dan melakukan kueri disediakan di sini . Dia memberikan beberapa detail tentang penyetelan rencana (untuk memaksa lebih banyak pekerja untuk ditindaklanjuti) di sini . Penting untuk dicatat bahwa skrip paralel melibatkan banyak tugas koordinasi, sehingga batas teoretis ekstrim untuk memberikan paralelisasi paling ekstrem tidak berlaku dalam praktik, karena jaringan, dan karakteristik desain sistem lainnya.
sumber