Выбор 3 ближайших мест с использованием базы данных широта-долгота-почтовый индекс - PullRequest
0 голосов
/ 04 марта 2011

У меня есть небольшая проблема с производительностью моего скрипта, поэтому мне интересно, если кто-нибудь знает лучший способ подойти к этому.

У меня есть база данных с местоположениями и их почтовыми индексами (идентификатор, имя, почтовый индекс).В другой таблице у меня есть широта и долгота, связанные с почтовыми индексами (широта, лонг, почтовый индекс).Сценарий запрашивает у пользователя почтовый индекс и возвращает 3 ближайших местоположения.

Сначала я делаю это следующим образом: сначала я получаю все местоположения из базы данных в локальный массив, а затем использую запрос mysql.Я получаю расстояния между местоположением и почтовым индексом пользователя для каждого местоположения.

SELECT SQRT( POW( (
    uc1.lat - uc2.lat
    ), 2 ) + POW( (
    uc1.long - uc2.long
    ), 2 ) ) 
FROM postcodes uc1
LEFT JOIN postcodes uc2 ON uc1.postcode = "$postcode1"
WHERE uc2.code = "$psotcode2"

После этого я сортирую массив и отображаю первые 3 элемента.

Это прекрасно работает, если количество мест невелико, но по мере приближения к тысячам производительность становится проблемой.

Есть идеи?

РЕДАКТИРОВАТЬ: Я вполне осведомлен о кривизне Земли.Я разместил этот запрос вместо более математически сложного, чтобы было легче понять, что на самом деле происходит

Ответы [ 2 ]

1 голос
/ 04 марта 2011

Создайте «ограничивающий прямоугольник» для использования в предложении WHERE в вашем SQL-запросе, как описано в этой статье о Movable Type (с примерами кода PHP), затем включите формулу Haversine в ваш запрос для вычисленияфактические расстояния и упорядочите результат по расстоянию ASC.

Это ограничивающий прямоугольник помогает вашей производительности, потому что это означает, что вы выполняете дорогостоящий расчет расстояния только на небольшом подмножестве ваших данных

0 голосов
/ 04 марта 2011

Во-первых, ваш расчет расстояния не учитывает кривизну земли

Вы должны взглянуть на что-то подобное

SELECT id, place_name,
((ACOS(SIN($lat * PI() / 180) * SIN(`lat` * PI() / 180) + COS($lat * PI() / 180) * COS(`lat` * PI() / 180) * COS(($lon – `lon`) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS distance
FROM places
ORDER BY distance ASC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...