sql >> Base de Datos >  >> RDS >> PostgreSQL

Consulta espacial en una tabla grande con múltiples uniones automáticas con un rendimiento lento

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: