Mempercepat permintaan OpenStreetMap PostGIS

12

Saya memiliki data OpenStreetMap untuk Belanda yang dimuat ke dalam database PostGIS (PostgreSQL 8.3 / PostGIS 1.3.3) menggunakan skema osmosis . Ini berarti semua tag disimpan di bidang hstore . Selain indeks GIST yang dibuat osmosis pada bidang geometri, saya membuat indeks GIST tambahan pada bidang tag.

Mencoba membuat kueri menggunakan batasan spasial dan batasan pada bidang tag, saya menemukan bahwa ini lebih lambat daripada yang saya inginkan. Kueri seperti ini:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

Dibutuhkan 22 detik untuk mengembalikan 78 catatan.

Ada sekitar 53 juta catatan dalam tabel ini.

Apakah ada cara untuk mempercepat ini secara signifikan? Saya pernah mendengar bahwa hstore diimplementasikan secara signifikan lebih baik di PostgreSQL 9, akankah meningkatkan bantuan?

mvexel
sumber
Karena ini sepertinya pertanyaan yang berorientasi pada database, saya mendorong Anda untuk bertanya di dba.stackexchange.com
jcolebrand
Pembaruan untuk 2015 - PostGIS telah membuat peningkatan kinerja yang signifikan sejak pertanyaan ini diajukan, jadi pertimbangkan juga pembaruan PostgreSQL.
Toby Speight

Jawaban:

5

Salah satu metode adalah dengan menanyakan tag yang Anda minati dan menempatkan catatan tersebut di tabel baru. Maka Anda hanya perlu meminta tabel baru alih-alih semua 53 juta catatan. Jika Anda mencoba untuk memperbarui basis data Anda, Anda bisa menjalankan kueri ini setiap kali Anda mendapatkan data baru dari OSM.

jvangeld
sumber
2
Daripada membuat tabel baru, Anda dapat mempertimbangkan membuat VIEW, dengan cara itu Anda "query" langsung ditautkan ke data sumber asli Anda tanpa duplikasi data secara literal.
RyanKDalton
7
Tampilan tidak akan serta merta meningkatkan kinerja kueri, kecuali jika itu adalah tampilan material atau setara (lihat pertanyaan SO tentang topik ini). Saya tidak percaya Postgresql mendukung pandangan terwujud secara langsung, tetapi mereka dapat diimplementasikan menggunakan pemicu.
Adam Armor
2
Ini adalah solusi yang saya gunakan saat ini. Setelah pembaruan ke tabel osmosis, saya kembali membuat beberapa tabel yang dioptimalkan untuk kueri yang ingin saya jalankan. Saya hanya merasa harus ada cara yang lebih baik. Topik pemicu membuat saya penasaran, dan bagaimana Anda bisa menggunakannya untuk mengimplementasikan pandangan materi. @Adam Armor, ada kemungkinan Anda bisa berbagi wawasan tentang ini?
mvexel
4
@mvexel Lihatlah artikel wiki ini , yang mencakup dasar-dasar pandangan terwujud dan detail bagaimana mengimplementasikannya di PostgreSQL.
Adam Armor
5

Anda dapat mencoba membuat indeks untuk kolom hstore Anda,

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

dan kemudian gunakan ?operator untuk membatasi kueri hanya pada baris itu:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));
olt
sumber
Terima kasih! Saya sudah membuat indeks itu, hanya saja saya tidak menggunakannya. Ini hanya mempercepat operasi tertentu. Di PostgreSQL 8.3 (yang saya gunakan) hanya @> dan? , di 9.0 adalah @>,?,? & dan? | .
mvexel
1
Sebagai catatan, permintaan menggunakan ?operator membutuhkan waktu 48 detik dibandingkan dengan 88 detik untuk permintaan saya (saya tidak tahu bagaimana saya mendapat 72 detik kemarin, mungkin mesin melakukan sesuatu yang rumit saat ini ketika saya melakukan query). Jadi masih bukan kinerja yang saya cari, tapi saya mendapatkan pemahaman yang lebih dalam tentang bagaimana indeks GIST beroperasi pada kolom hstore. Saya masih harus pergi dengan solusi lain untuk menciptakan pandangan terwujud untuk mendapatkan kinerja yang saya inginkan.
mvexel
3

Fungsi st_within dan _st_within tidak dikenal karena kecepatannya. Operator && mungkin membantu karena akan memeriksa kotak bukan geometri

Anda dapat mencoba yang berikut ini:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND geom && ST_SetSRID('BOX3D(4 52,5 53)'::box3d,4326);

Untuk kiat kinerja lebih lanjut, periksa: http://postgis.refractions.net/docs/ch06.html

milovanderlinden
sumber
2

Masalah dengan permintaan Anda adalah tags->'man_made'='surveillance'klausa. Ini memaksa Postgres untuk memperluas tag hstore dan tidak mengizinkannya untuk menggunakan indeks. Jika Anda menulis ulang ini menggunakan @>(mengandung) itu akan memungkinkan penggunaan indeks.

Karena Anda meminta persegi panjang, Anda dapat menggunakan &&sebagai ganti ST_Within. Ini akan memiliki keuntungan kecil, karena ST_Within tidak rumit untuk dievaluasi, dan ST_Within secara implisit melakukan &&pemeriksaan.

Peningkatan kecepatan tambahan akan menggunakan indeks GIN pada tag, bukan indeks GIST. Indeks GIN membutuhkan waktu lebih lama untuk dibangun tetapi lebih cepat.

Seluruh kueri akan menjadi

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n INNER JOIN users AS u ON n.user_id = u.id WHERE tags @> hstore('man_made', 'surveillance') AND geom && ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326);

Jika Anda tahu Anda akan sering meminta tag tertentu, Anda dapat membuat sebagian indeks dengan itu CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);.

Ini akan memungkinkan kondisi WHERE tags->'man_made'='surveillance'untuk menggunakan indeks. Sayangnya, indeks itu tidak dapat membantu @>kueri dan indeks GIN atau GIST tidak dapat membantu tags->'foo'kueri, jadi Anda harus mencocokkan kueri dengan indeks yang Anda miliki.

Paul Norman
sumber
Saran untuk menggunakan tags @>hstore()kueri saya secara besar-besaran, terima kasih.
alphabetasoup
1

coba ini sebagai gantinya:

PILIH n.geom, n.tags, n.tstamp, u.name DARI node AS n INNER GABUNG pengguna SEBAGAI ON n.user_id = u.id WHERE tags @> 'man_made => surveillance' :: hstore AND ST_Within (geom , ST_GeomFromText ('POLYGON ((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))', 4326));

LR1234567
sumber