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: