Đầu tiên , sử dụng
ST_SetSRID(ST_MakePoint(c.longitude, c.latitude),4326)::geography
thay vì
ST_GeographyFromText('SRID=4326;POINT(' || c.longitude || ' ' || c.latitude || ')')
Mỗi tài liệu:
ST_MakePoint
trong khi không tuân thủ OGC thường nhanh hơn và chính xác hơn ST_GeomFromText
và ST_PointFromText
. Nó cũng dễ sử dụng hơn nếu bạn có tọa độ thô thay vì WKT.
Tiếp theo , để làm cho truy vấn ngắn hơn và chỉ nhập tham số tìm kiếm một lần (không ảnh hưởng nhiều đến hiệu suất), hãy sử dụng truy vấn con (hoặc CTE):
SELECT id
, ST_Distance(t.x
, ST_SetSRID(ST_MakePoint(c.longitude, c.latitude),4326)::geography) AS dist
FROM cafes c
, (SELECT ST_GeographyFromText('SRID=4326;POINT(-76.000000 39.000000)')) AS t(x)
WHERE ST_DWithin(t.x
, ST_SetSRID(ST_MakePoint(c.longitude, c.latitude),4326)::geography, 2000)
ORDER BY dist;
Cuối cùng , bạn cần một chỉ số GiST để thực hiện điều này nhanh chóng cho các bảng lớn.
Mỗi tài liệu vềST_DWithin()
:
Cuộc gọi chức năng này sẽ tự động bao gồm một so sánh hộp giới hạn sẽ sử dụng bất kỳ chỉ mục nào có sẵn trên hình học.
Bạn có thể làm điều này để làm việc với một chỉ mục chức năng trên biểu thức khi bắt đầu câu trả lời. Nhưng tôi sẽ lưu trữ một geography
cột loại để bắt đầu (hãy đặt tên cho nó thegeog
) và tạo một chỉ mục GiST đơn giản như:
CREATE INDEX cafes_thegeog_gist ON cafes USING gist(thegeog);
Đến với truy vấn đơn giản hơn và nhanh hơn nhiều này:
SELECT id, ST_Distance(t.x, thegeog) AS distance
FROM cafes c
, (SELECT ST_GeographyFromText('SRID=4326;POINT(-76.000000 39.000000)')) AS t(x)
WHERE ST_DWithin(t.x, thegeog, 2000)
ORDER BY distance;
Cập nhật để phù hợp geography
với geography
, như được chỉ ra bởi @ LR1234567 trong bình luận. Thay thế, bạn có thể làm việc với geometry
. Tất cả các chức năng được sử dụng ở đây đều hoạt động cho cả hai (ngoại trừ ST_MakePoint
, do đó, dàn diễn viên được nối thêm). Có gì khác biệt?
Nếu bạn muốn có n quán cà phê gần nhất thay vì tất cả trong bán kính, hãy xem xét tìm kiếm "hàng xóm gần nhất" . Thường thuận tiện hơn.
WHERE
mệnh đề của bạn ? Giống như so sánh nó với một ngưỡng?