Kueri ini harus berjalan jauh (menjadi banyak lebih cepat):
WITH school AS (
SELECT s.osm_id AS school_id, text 'school' AS type, s.osm_id, s.name, s.way_geo
FROM planet_osm_point s
, LATERAL (
SELECT 1 FROM planet_osm_point
WHERE ST_DWithin(way_geo, s.way_geo, 500, false)
AND amenity = 'bar'
LIMIT 1 -- bar exists -- most selective first if possible
) b
, LATERAL (
SELECT 1 FROM planet_osm_point
WHERE ST_DWithin(way_geo, s.way_geo, 500, false)
AND amenity = 'restaurant'
LIMIT 1 -- restaurant exists
) r
WHERE s.amenity = 'school'
)
SELECT * FROM (
TABLE school -- schools
UNION ALL -- bars
SELECT s.school_id, 'bar', x.*
FROM school s
, LATERAL (
SELECT osm_id, name, way_geo
FROM planet_osm_point
WHERE ST_DWithin(way_geo, s.way_geo, 500, false)
AND amenity = 'bar'
) x
UNION ALL -- restaurants
SELECT s.school_id, 'rest.', x.*
FROM school s
, LATERAL (
SELECT osm_id, name, way_geo
FROM planet_osm_point
WHERE ST_DWithin(way_geo, s.way_geo, 500, false)
AND amenity = 'restaurant'
) x
) sub
ORDER BY school_id, (type <> 'school'), type, osm_id;
Ini bukan sama dengan kueri asli Anda, melainkan apa yang sebenarnya Anda inginkan, sesuai diskusi di komentar :
Jadi kueri ini mengembalikan daftar sekolah tersebut, diikuti oleh bar dan restoran terdekat. Setiap set baris disatukan oleh osm_id
sekolah pada kolom school_id
.
Sekarang menggunakan LATERAL
bergabung, untuk memanfaatkan indeks spasial GiST.
TABLE school
hanyalah singkatan dari SELECT * FROM school
:
Ekspresi (type <> 'school')
memesan sekolah di setiap set terlebih dahulu, karena:
Subkueri sub
di akhir SELECT
hanya diperlukan untuk memesan dengan ekspresi ini. Sebuah UNION
kueri membatasi ORDER BY
attached terlampir daftar ke kolom saja, tanpa ekspresi.
Saya fokus pada pertanyaan yang Anda sajikan untuk tujuan jawaban ini - mengabaikan persyaratan tambahan untuk memfilter pada salah satu dari 70 kolom teks lainnya. Itu benar-benar cacat desain. Kriteria pencarian harus terkonsentrasi di sedikit kolom. Atau Anda harus mengindeks semua 70 kolom, dan indeks multikolom seperti yang akan saya usulkan bukanlah pilihan. Masih mungkin meskipun ...
Indeks
Selain yang sudah ada:
"idx_planet_osm_point_waygeo" gist (way_geo)
Jika selalu memfilter pada kolom yang sama, Anda dapat membuat indeks multikolom mencakup beberapa kolom yang Anda minati, jadi index- hanya memindai menjadi mungkin:
CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)
Postgres 9.5
Postgres mendatang 9.5 memperkenalkan perbaikan besar yang terjadi untuk menangani kasus Anda dengan tepat:
Itu sangat menarik bagi Anda. Sekarang Anda dapat memiliki tunggal multicolumn (mencakup) indeks GiST:
CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)
Dan:
Dan:
Mengapa? Karena ROLLUP
akan menyederhanakan kueri yang saya sarankan. Jawaban terkait:
Versi alfa pertama telah dirilis pada 2 Juli 2015. Jadwal waktu rilis yang diharapkan:
Dasar
Tentu saja, pastikan untuk tidak mengabaikan dasar-dasarnya: