Deze zoekopdracht zou een lange weg moeten gaan (be veel sneller):
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;
Dit is niet hetzelfde als uw oorspronkelijke vraag, maar eerder wat u eigenlijk wilt, volgens discussie in opmerkingen :
Deze zoekopdracht retourneert dus een lijst van die scholen, gevolgd door bars en restaurants in de buurt. Elke reeks rijen wordt bij elkaar gehouden door de osm_id
van de school in de kolom school_id
.
Gebruikt nu LATERAL
joins, om gebruik te maken van de ruimtelijke GiST-index.
TABLE school
is gewoon een afkorting voor SELECT * FROM school
:
De uitdrukking (type <> 'school')
bestelt eerst de school in elke set, omdat:
De subquery sub
in de laatste SELECT
is alleen nodig om te bestellen met deze uitdrukking. Een UNION
query beperkt een bijgevoegde ORDER BY
lijst naar alleen kolommen, geen uitdrukkingen.
Ik concentreer me op de vraag die u heeft gesteld voor dit antwoord - negeren de uitgebreide vereiste om te filteren op een van de andere 70 tekstkolommen. Dat is echt een ontwerpfout. De zoekcriteria moeten worden geconcentreerd in enkele kolommen. Of je moet alle 70 kolommen indexeren, en indexen met meerdere kolommen, zoals ik ga voorstellen, zijn nauwelijks een optie. Nog mogelijk hoewel ...
Index
Naast de bestaande:
"idx_planet_osm_point_waygeo" gist (way_geo)
Als u altijd op dezelfde kolom filtert, kunt u een maken index met meerdere kolommen voor de paar kolommen waarin u geïnteresseerd bent, dus index- scant alleen mogelijk worden:
CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)
Postgres 9.5
De komende Postgres 9.5 introduceert grote verbeteringen die toevallig uw zaak precies behandelen:
Dat is voor jou van bijzonder belang. Nu kunt u een enkele . hebben multicolumn (bedekkende) GiST-index:
CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)
En:
En:
Waarom? Omdat ROLLUP
zou de door mij voorgestelde vraag vereenvoudigen. Gerelateerd antwoord:
De eerste alfaversie is uitgebracht op 2 juli 2015. De verwachte tijdlijn voor de release:
Basis
Zorg er natuurlijk voor dat u de basis niet over het hoofd ziet: