PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Consulta espacial em uma tabela grande com várias autojunções com lentidão


Esta consulta deve percorrer um longo caminho (ser muito mais 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;

Isso não o mesmo que sua consulta original, mas sim o que você realmente deseja, conforme discussão nos comentários :

Portanto, essa consulta retorna uma lista dessas escolas, seguidas de bares e restaurantes próximos. Cada conjunto de linhas é mantido junto pelo osm_id da escola na coluna school_id .

Agora usando LATERAL joins, para fazer uso do índice espacial GiST.

MESA escola é apenas um atalho para SELECT * FROM school :

A expressão (type <> 'school') ordena a escola em cada conjunto primeiro, porque:

A subconsulta sub no SELECT final só é necessário ordenar por esta expressão. Uma UNION consulta limita um ORDER BY anexado list para apenas colunas, sem expressões.

Concentro-me na consulta que você apresentou para esta resposta - ignorando o requisito estendido para filtrar qualquer uma das outras 70 colunas de texto. Isso é realmente uma falha de projeto. Os critérios de pesquisa devem estar concentrados em poucos colunas. Ou você terá que indexar todas as 70 colunas, e índices de várias colunas, como vou propor, dificilmente são uma opção. Ainda possível no entanto ...

Índice


Além dos já existentes:
"idx_planet_osm_point_waygeo" gist (way_geo)

Se estiver sempre filtrando na mesma coluna, você pode criar um índice de várias colunas cobrindo as poucas colunas em que você está interessado, então index- apenas digitalizações tornar possível:
CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)

Postgres 9.5


O próximo Postgres 9.5 apresenta grandes melhorias que acontecem para resolver o seu caso exatamente:

Isso é de particular interesse para você. Agora você pode ter um único índice GiST de várias colunas (cobrindo):
CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)

E:

E:

Por quê? Porque ROLLUP simplificaria a consulta que sugeri. Resposta relacionada:

A primeira versão alfa foi lançada em 2 de julho de 2015. O cronograma esperado para o lançamento:

Noções básicas


Claro, certifique-se de não negligenciar o básico: