Den här frågan borde räcka långt (vara mycket snabbare):
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;
Detta är inte samma som din ursprungliga fråga, utan snarare vad du faktiskt vill ha, enligt diskussion i kommentarer :
Så den här frågan returnerar en lista över dessa skolor, följt av barer och restauranger i närheten. Varje uppsättning rader hålls samman av osm_id
av skolan i kolumnen school_id
.
Använder nu LATERAL
joins, för att använda det rumsliga GiST-indexet.
TABELL skola
är bara en förkortning för SELECT * FROM school
:
Uttrycket (typ <> 'skola')
beställer skolan i varje set först, eftersom:
Underfrågan sub
i den sista SELECT
behövs bara för att beställa efter detta uttryck. En UNION
fråga begränsar en bifogad ORDER BY
lista till endast kolumner, inga uttryck.
Jag fokuserar på frågan du presenterade för detta svar - ignorera det utökade kravet att filtrera på någon av de andra 70 textkolumnerna. Det är verkligen ett designfel. Sökkriterierna bör koncentreras till få kolumner. Eller så måste du indexera alla 70 kolumner, och flerkolumnsindex som jag kommer att föreslå är knappast ett alternativ. Fortfarande möjligt fast ...
Index
Förutom de befintliga:
"idx_planet_osm_point_waygeo" gist (way_geo)
Om du alltid filtrerar på samma kolumn kan du skapa en flerkolumnsindex täcker de få kolumner du är intresserad av, så index- endast skannar bli möjligt:
CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)
Postgres 9.5
Den kommande Postgres 9.5 introducerar stora förbättringar som råkar adressera ditt fall exakt:
Det är av särskilt intresse för dig. Nu kan du ha en singel flerkolumn (täckande) GiST-index:
CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)
Och:
Och:
Varför? Eftersom ROLLUP
skulle förenkla frågan jag föreslog. Relaterat svar:
Den första alfaversionen har släppts den 2 juli 2015. Den förväntade tidslinjen för releasen:
Grunderna
Naturligtvis, se till att inte förbise grunderna: