Truy vấn này sẽ đi một chặng đường dài (được nhiều nhanh hơn):
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;
Đây là không giống như truy vấn ban đầu của bạn, nhưng đúng hơn là những gì bạn thực sự muốn, theo thảo luận trong nhận xét :
Vì vậy, truy vấn này trả về danh sách các trường đó, theo sau là các quán bar và nhà hàng gần đó. Mỗi nhóm hàng được tổ chức với nhau bằng osm_id
của trường trong cột school_id
.
Hiện đang sử dụng LATERAL
tham gia, để sử dụng chỉ mục GiST không gian.
trường TABLE
chỉ là viết tắt của SELECT * FROM school
:
Biểu thức (type <> 'school')
đặt hàng trường học trong mỗi tập hợp trước, bởi vì:
Truy vấn con sub
trong SELECT
cuối cùng chỉ cần thiết để sắp xếp theo biểu thức này. Một UNION
truy vấn giới hạn ORDER BY
đính kèm chỉ liệt kê các cột, không có biểu thức.
Tôi tập trung vào truy vấn bạn đã trình bày cho mục đích của câu trả lời này - bỏ qua yêu cầu mở rộng để lọc trên bất kỳ cột văn bản nào trong số 70 cột văn bản khác. Đó thực sự là một lỗ hổng thiết kế. Tiêu chí tìm kiếm nên được tập trung ở vài cột. Hoặc bạn sẽ phải lập chỉ mục tất cả 70 cột và các chỉ mục đa cột như tôi sắp đề xuất hầu như không phải là một lựa chọn. Vẫn có thể mặc dù ...
Chỉ mục
Ngoài cái hiện có:
"idx_planet_osm_point_waygeo" gist (way_geo)
Nếu luôn lọc trên cùng một cột, bạn có thể tạo chỉ mục nhiều cột bao gồm một số cột mà bạn quan tâm, vì vậy index- chỉ quét trở nên khả thi:
CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)
Postgres 9.5
Postgres sắp ra mắt 9.5 giới thiệu những cải tiến lớn điều đó xảy ra để giải quyết chính xác trường hợp của bạn:
Đó là mối quan tâm đặc biệt cho bạn. Bây giờ bạn có thể có một đĩa đơn chỉ số GiST đa cột (bao trùm):
CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)
Và:
Và:
Tại sao? Bởi vì ROLLUP
sẽ đơn giản hóa truy vấn mà tôi đã đề xuất. Câu trả lời liên quan:
Phiên bản alpha đầu tiên đã được phát hành vào ngày 2 tháng 7 năm 2015. Tiến trình dự kiến cho bản phát hành:
Kiến thức cơ bản
Tất nhiên, hãy chắc chắn không bỏ qua những điều cơ bản: