Bagaimana cara memperbaiki masalah kinerja di PostGIS ST_Intersects?

9

Saya seorang pemula di postgis dan saya memiliki masalah dalam kinerja permintaan.

Ini pertanyaan saya:

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes here',4326),position) 
ORDER BY userid, timestamp desc

dan masalahnya adalah multipoligon saya termasuk poligon SANGAT besar (panjang 600 halaman dalam kata doc!) dan butuh lebih dari 2 jam untuk mengeksekusi!

Apakah ada cara untuk mengoptimalkan permintaan saya atau menggunakan cara lain?

Tolong bantuan Anda sangat dihargai!

Sara
sumber

Jawaban:

8

Yang harus Anda lakukan adalah meletakkan multipolygon besar Anda dalam sebuah tabel sebagai poligon tunggal (dengan ST_Dump) dan meletakkan indeks di atasnya. Sesuatu seperti:

CREATE TABLE big_polygon as
SELECT (ST_Dump( ST_GeomFromText('a multiypolygon geom goes here',4326))).geom as geom;

-- It is always great to put a primary key on the table
ALTER table big_polygon ADD Column gid serial PRIMARY KEY;

-- Create the index
CREATE INDEX idx_big_polygon_geom
on big_polygon
USING gist(geom);

-- To give the database some information about how the index looks
analyze big_polygon;

-- Then you go:
SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1, big polygon WHERE ST_Intersects ( big_polygon.geom,position) 
ORDER BY userid, timestamp desc;

Itu harus lebih cepat karena beberapa alasan.

Nicklas Avén
sumber
Terima kasih Nicklas atas balasan yang luar biasa ini. Maaf saya melewatkan menyebutkan bahwa saya memiliki lebih dari satu poligon dan mereka sudah disimpan dalam tabel dengan indeks. Tapi saya kira menyediakan data geom secara langsung akan lebih cepat. Namun, saya mencoba cara yang Anda sarankan tetapi itu masih memakan waktu yang sangat lama! ada saran lain?
Sara
@Sara. Ok, jadi Anda mencoba membagi multigeoemtries menjadi geometri tunggal seperti yang saya sarankan dengan ST_Dump?
Nicklas Avén
Berapa banyak posisi pengguna yang kita bicarakan? Berapa banyak poligon besar? Apa yang Anda dapatkan dari SELECT ST_npoints (geom) dari big_polygons_table ;?
Nicklas Avén
Maaf saya salah, izinkan saya menjelaskan lebih lanjut tentang tabel saya untuk membuatnya lebih jelas untuk Anda: Saya punya table1 yang mencakup kolom geom yang memiliki sekitar 230 baris dan di setiap baris ada multipoligon (mereka mewakili negara sehingga ukurannya bervariasi) , dan indeks di kolom the_geom. Table2 yang meliputi kolom posisi (poin), timestamp, userid dan id (pk) dan 3 indeks dibuat menggunakan (posisi, timestamp, userid). Tabel ini sangat besar tentang 103496003 baris. Jumlah maksimum dari ST_npoints adalah 1440430 dan jumlah min adalah 16. Maaf jika saya membuat Anda bingung tetapi saya benar-benar membutuhkan bantuan Anda! Terima kasih
Sara
2

Tergantung jenis kualitas - ketelitian yang Anda butuhkan. Anda jelas dapat menyederhanakan poligon dengan menggunakan: http://postgis.net/docs/ST_Simplify.html

Apa yang sering saya lakukan selama pengembangan aplikasi GIS saya adalah memikirkan cara terbaik untuk meminimalkan data. Misalnya. pilih dulu poligon di dalam kotak batas misalnya. - Bergantung pada tingkat zoom Anda tidak perlu hasil yang sangat presisi (st_simplify) begitu ...

Semoga itu sedikit membantu Anda!

Styp
sumber
Terima kasih Martin atas tanggapan cepat Anda. Masalah saya adalah saya perlu hasilnya sangat akurat sehingga saya pikir fungsi ini tidak akan membantu saya di sini! tapi Terima kasih atas sarannya
Sara
0

Bergantung pada keahlian postgres dan / atau sql Anda, Anda memiliki beberapa opsi:

  1. menganalisis kueri melalui perintah EXPLAIN untuk mencari tahu apakah Anda menekan hambatan tertentu. Peringatan: kadang-kadang output EXPLAIN mungkin sulit dipahami

  2. jika Anda berharap bahwa sebagian besar atau sebagian besar geometri dalam tabel1 JANGAN memotong berpoligon, Anda bisa mencoba menerapkan kondisi pendahuluan terhadap poligon yang lebih sederhana (yaitu dengan memecah multiploygon dalam potongan yang lebih kecil) dan kemudian jalankan persimpangan multipoligon yang lebih berat hanya pada hasil tersebut. Lihat di bawah untuk contoh.

  3. jika dan hanya jika CPU adalah hambatan (yaitu server macet di persimpangan komputer) Saya sepenuhnya menyarankan Anda mendapatkan CPU yang lebih besar, lebih cepat, lebih kuat atau menyewa Instance CPU Tinggi satu kali dari EC2 Amazon dan menghancurkannya ketika Anda selesai

Contoh permintaan untuk item 2:

SELECT DISTINCT ON (st1.userid) st1.userid ,ST_AsText(st1.position), st1.timestamp  
FROM (
    select userid, position, timestamp from table1 
    WHERE ST_Intersects ( YOUR_MULTIPOL_BOUNDS_HERE,position)
) as st1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes     here',4326),st1.position) 
ORDER BY st1.userid, st1.timestamp desc

Untuk meningkatkan kinerja, Anda juga dapat secara sementara mematerialisasi subselect st1 sebagai tabel sehingga Anda dapat mengindeksnya.

@Nicklas benar untuk menunjukkan dalam komentar bahwa contoh untuk saran 2 seharusnya tidak membantu. Dia benar, tapi saya pikir saya juga (sebagian) benar.

Bahkan sepertinya pertanyaan yang sangat mirip ditanyakan (dan dijawab) pada November lalu di postgis ML:

http://postgis.refractions.net/pipermail/postgis-users/2011-November/031344.html

dan ternyata sarannya adalah untuk benar-benar memecah poligon sehingga indeks paling efektif dapat memfilter persimpangan palsu yang akan dipicu oleh pemeriksaan batas sederhana.

unicoletti
sumber
saran 2 seharusnya tidak membantu karena itulah yang dilakukan indeks. Sehingga konstruk itu akan melakukan hal yang sama sekali lagi.
Nicklas Avén
@ NicklasAvén Anda benar, saya mengubah jawabannya
unicoletti
0

Menggunakan ST_SubDivide()

Untuk Postgis versi 2.2, Anda dapat menggunakan ST_SubDivide.

ST_Subdivide - Mengembalikan set geometri di mana tidak ada geometri dalam set memiliki lebih dari jumlah simpul yang ditentukan.

setof geometry ST_Subdivide(geometry geom, integer max_vertices=256);

Anda juga bisa

  • gunakan tabel temp
  • sebuah indeks

Di sini kita gunakan ST_SubDivideuntuk memecah poligon menjadi subpoligon dengan 10 atau lebih sedikit simpul.

CREATE TEMP TABLE divided AS
SELECT ST_SubDivide(bigmultipolygon,10)::geometery AS t(geom);

CREATE INDEX divided_idx ON divided USING gist(geom);

Kemudian

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1
JOIN divided AS d
  ON ST_Intersects( d.geom, position )
ORDER BY userid, timestamp desc;

Jangan lakukan hal di atas, itu menyebabkan kesalahan pembulatan

Tuning Umum

Lihat juga bagian yang berjudul Tip Kinerja dalam dokumen. Pastikan Anda disetel dengan tepat. Pertimbangkan meningkatkan max_parallel_workers_per_gatheruntuk memanfaatkan paralelisasi (saat ini default tidak aktif).

Evan Carroll
sumber