To zapytanie powinno zająć dużo czasu (być dużo szybciej):
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;
To nie takie samo jak oryginalne zapytanie, ale raczej to, czego faktycznie chcesz, zgodnie z dyskusją w komentarzach :
To zapytanie zwraca więc listę tych szkół, a następnie pobliskich barów i restauracji. Każdy zestaw wierszy jest utrzymywany razem przez osm_id
szkoły w kolumnie school_id
.
Teraz używam LATERAL
łączy, aby wykorzystać przestrzenny indeks GiST.
Table szkoła
to tylko skrót od SELECT * FROM school
:
Wyrażenie (wpisz <> 'szkoła')
najpierw zamawia szkołę w każdym zestawie, ponieważ:
Podzapytanie sub
w końcowym SELECT
jest potrzebne tylko do uporządkowania według tego wyrażenia. ZWIĄZEK
zapytanie ogranicza dołączone ORDER BY
lista tylko do kolumn, bez wyrażeń.
Skupiam się na zapytaniu, które przedstawiłeś w celu udzielenia tej odpowiedzi – ignorowanie rozszerzony wymóg filtrowania według dowolnej z pozostałych 70 kolumn tekstowych. To naprawdę wada projektowa. Kryteria wyszukiwania powinny być skoncentrowane w niewielu kolumny. Albo będziesz musiał zaindeksować wszystkie 70 kolumn, a indeksy wielokolumnowe, które zamierzam zaproponować, nie są żadną opcją. Nadal możliwe chociaż ...
Indeks
Oprócz istniejących:
"idx_planet_osm_point_waygeo" gist (way_geo)
Jeśli zawsze filtrujesz tę samą kolumnę, możesz utworzyć indeks wielokolumnowy obejmujące kilka interesujących Cię kolumn, więc index- tylko skanuje stać się możliwe:
CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)
Postgres 9.5
Nadchodzący Postgres 9,5 wprowadza duże ulepszenia które dokładnie odpowiadają Twojej sprawie:
To dla ciebie szczególnie interesujące. Teraz możesz mieć singiel wielokolumnowy (zakrywający) indeks GiST:
CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)
Oraz:
Oraz:
Czemu? Ponieważ ROLLUP
uprościłoby zapytanie, które zasugerowałem. Powiązana odpowiedź:
Pierwsza wersja alfa została wydana 2 lipca 2015 r. Przewidywany harmonogram wydania:
Podstawy
Oczywiście nie zapomnij o podstawach: