Esta consulta debería recorrer un largo camino (ser mucho más rápido):
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;
Esto es no lo mismo que su consulta original, pero más bien lo que realmente desea, según la discusión en los comentarios :
Entonces, esta consulta devuelve una lista de esas escuelas, seguida de bares y restaurantes cercanos. Cada conjunto de filas se mantiene unido por osm_id
de la escuela en la columna school_id
.
Ahora usando LATERAL
se une, para hacer uso del índice GiST espacial.
TABLE school
es solo una abreviatura de SELECT * FROM school
:
La expresión (type <> 'school')
ordena la escuela en cada conjunto primero, porque:
La subconsulta sub
en el SELECT
final solo se necesita ordenar por esta expresión. UNA UNION
la consulta limita un ORDER BY
adjunto lista a solo columnas, sin expresiones.
Me concentro en la consulta que presentó a los efectos de esta respuesta - ignorar el requisito extendido para filtrar en cualquiera de las otras 70 columnas de texto. Eso es realmente un defecto de diseño. Los criterios de búsqueda deben concentrarse en pocos columnas O tendrá que indexar las 70 columnas, y los índices de varias columnas como voy a proponer no son una opción. Todavía posible aunque...
Índice
Además de los existentes:
"idx_planet_osm_point_waygeo" gist (way_geo)
Si siempre filtra en la misma columna, puede crear un índice de varias columnas cubriendo las pocas columnas que le interesan, así que index- solo escaneos ser posible:
CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)
Postgres 9.5
El próximo Postgres 9.5 introduce mejoras importantes que suceden para abordar su caso exactamente:
Eso es de particular interés para usted. Ahora puedes tener un sencillo Índice GiST multicolumna (cubierta):
CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)
Y:
Y:
¿Por qué? Porque ROLLUP
simplificaría la consulta que sugerí. Respuesta relacionada:
La primera versión alfa se lanzó el 2 de julio de 2015. La línea de tiempo esperada para el lanzamiento:
Conceptos básicos
Por supuesto, asegúrese de no pasar por alto los conceptos básicos: