Геолокационное расстояние SQL из таблицы городов - PullRequest
1 голос
/ 22 сентября 2011

Итак, у меня есть эта функция для расчета ближайших городов на основе параметров широты, долготы и радиуса.

DELIMITER $$
DROP PROCEDURE IF EXISTS `world_db`.`geolocate_close_cities`$$
CREATE PROCEDURE `geolocate_close_cities`(IN p_latitude DECIMAL(8,2), p_longitude DECIMAL(8,2), IN p_radius INTEGER(5))
BEGIN
        SELECT id, country_id, longitude, latitude, city,
        truncate((degrees(acos( sin(radians(latitude)) 
        * sin(radians(p_latitude)) 
        + cos(radians(latitude)) 
        * cos(radians(p_latitude)) 
        * cos(radians(p_longitude - longitude) ) ) ) 
        * 69.09*1.6),1) as distance 
        FROM cities
        HAVING distance < p_radius
        ORDER BY distance desc;
    END$$

DELIMITER ;

Вот структура таблицы моих городов:

> +------------+-------------+------+-----+---------+----------------+ |
> Field      | Type        | Null | Key | Default | Extra          |
> +------------+-------------+------+-----+---------+----------------+ |
> id         | int(11)     | NO   | PRI | NULL    | auto_increment | |
> country_id | smallint(6) | NO   |     | NULL    |                | |
> region_id  | smallint(6) | NO   |     | NULL    |                | |
> city       | varchar(45) | NO   |     | NULL    |                | |
> latitude   | float       | NO   |     | NULL    |                | |
> longitude  | float       | NO   |     | NULL    |                | |
> timezone   | varchar(10) | NO   |     | NULL    |                | |
> dma_id     | smallint(6) | YES  |     | NULL    |                | |
> code       | varchar(4)  | YES  |     | NULL    |                |
> +------------+-------------+------+-----+---------+----------------+

Работает очень хорошо.

То, что я хотел бы сделать (псевдокод), выглядит примерно так:

SELECT * FROM cities WHERE DISTANCE(SELECT id FROM cities WHERE id={cityId}, {km)) 

и мне вернутся ближайшие города.

Есть идеи, как мне это сделать?

В данный момент я просто вызываю функцию, затем перебираю идентификаторы в массив, а затем выполняю WHEREIN в таблице city, что, очевидно, не очень эффективно.

Любая помощь очень ценится. Благодаря.

Ответы [ 2 ]

1 голос
/ 22 сентября 2011

Если вы можете ограничить максимальное расстояние между вашими городами и местным положением, воспользуйтесь тем, что одна минута широты (север - юг) составляет одну морскую милю.

Поместите индекс в вашу таблицу широт.

Создайте себе сохраненную функцию haversine (lat1, lat2, long1, long2, unit) из формулы haversine, показанной в вашем вопросе. Смотри ниже

Затем сделайте это, учитывая mylatitude, mylongitude и mykm.

SELECT * 
  from cities a
 where :mylatitude >= a.latitude  - :mykm/111.12
   and :mylatitude <= a.latitude  + :mykm/111.12
   and haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM') <= :mykm
 order by haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM')

Это будет использовать ограничивающую рамку широты, чтобы грубо исключить города, которые находятся слишком далеко от вашей точки. Ваша СУБД будет использовать сканирование диапазона индекса в индексе широты, чтобы быстро выбрать строки в таблице городов, которые стоит рассмотреть. Затем он запустит вашу функцию haversine, со всеми математическими функциями синуса и косинуса, только в этих строках.

Я предлагаю широту, потому что расстояние долготы на земле зависит от широты.

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

(Извините за магическое число 111.12. Это количество километров в градусах широты, то есть в шестидесяти морских милях.)


См. Здесь для работоспособной функции расстояния.

Почему эта хранимая функция MySQL дает результаты, отличные от вычислений в запросе?

0 голосов
/ 22 сентября 2011

Я бы взглянул на этот другой вопрос . Это должно помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...