Тази заявка трябва да измине дълъг път (да бъде много по-бързо):
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;
Това ене същото като оригиналната ви заявка, но по-скоро това, което всъщност искате, според дискусията в коментарите :
Така че тази заявка връща списък с тези училища, последван от барове и ресторанти наблизо. Всеки набор от редове се държи заедно от osm_id
на училището в колоната school_id
.
Сега се използва LATERAL
се присъединява, за да използва пространствения GiST индекс.
Училище TABLE
е просто съкращение за SELECT * FROM school
:
Изразът (тип <> 'училище')
нарежда първо училището във всеки комплект, защото:
Подзаявката sub
в крайния SELECT
е необходимо само за подреждане по този израз. СЪЮЗ
заявката ограничава прикачен ORDER BY
списък само към колони, без изрази.
Съсредоточавам се върху заявката, която представихте за целите на този отговор - игнориране разширеното изискване за филтриране на която и да е от останалите 70 текстови колони. Това наистина е дефект в дизайна. Критериите за търсене трябва да бъдат концентрирани в няколко колони. Или ще трябва да индексирате всичките 70 колони, а многоколонните индекси, каквито ще предложа, едва ли са опция. Все още възможно въпреки че...
Индекс
В допълнение към съществуващите:
"idx_planet_osm_point_waygeo" gist (way_geo)
Ако винаги филтрирате една и съща колона, можете да създадете многоколонен индекс обхващайки няколкото колони, които ви интересуват, така че index- само сканира стане възможно:
CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)
Postgres 9.5
Предстоящият Postgres 9.5 въвежда основни подобрения които отговарят точно на вашия случай:
Това е от особен интерес за вас. Сега можете да имате сингъл многоколонен (покриващ) GiST индекс:
CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)
И:
И:
Защо? Тъй като ROLLUPкод>
ще опрости заявката, която предложих. Свързан отговор:
Първата алфа версия беше пусната на 2 юли 2015 г. Очакваният график за изданието:
Основни положения
Разбира се, не пропускайте основните неща: