У вас есть неплохая ссылка для поиска расстояния mySQL.
Забудьте об Oracle Spatial. Слишком много кода, слишком много сложностей, недостаточно добавить значение.
Вот запрос, который сделает трюк. Это использует расстояния в мили устава. EDIT Это исправляет ошибку, упомянутую mdarwin, ценой проверки на разделение, если вы попытаетесь использовать ее для местоположения на северном или южном полюсе.
SELECT id, city, LATITUDE, LONGITUDE, distance
FROM
(
SELECT id,
city,
LATITUDE, LONGITUDE,
(3959 * ACOS(COS(RADIANS(LATITUDE))
* COS(RADIANS(mylat))
* COS(RADIANS(LONGITUDE) - RADIANS(mylng))
+ SIN(RADIANS(LATITUDE))
* SIN(RADIANS(mylat))
))
AS distance,
b.mydst
FROM Cities
JOIN (
SELECT :LAT AS mylat,
:LONG AS mylng,
:RADIUS_LIMIT AS mydst
FROM DUAL
)b ON (1 = 1)
WHERE LATITUDE >= mylat -(mydst/69)
AND LATITUDE <= mylat +(mydst/69)
AND LONGITUDE >= mylng -(mydst/(69 * COS(RADIANS(mylat))))
AND LONGITUDE <= mylng +(mydst/(69 * COS(RADIANS(mylat))))
)a
WHERE distance <= mydst
ORDER BY distance
Если вы работаете в километрах, изменить mydst/69 для mydst/111,045, и изменить 3959 на 6371.4. (1/69 конвертирует мили в градусы, 3959 - значение радиуса планеты.)
Теперь у вас, вероятно, возникнет соблазн использовать этот большой запрос как «волшебный черный ящик». Не делай этого! Это не очень сложно понять, и если вы поймете это, вы сможете сделать лучшую работу. Вот что происходит.
Этот раздел является основой того, что делает запрос быстрым. Он выполняет поиск в таблице городов для близлежащих городов до указанной вами точки.
WHERE LATITUDE >= mylat -(mydst/69)
AND LATITUDE <= mylat +(mydst/69)
AND LONGITUDE >= mylng -(mydst/(69 * COS(RADIANS(mylat))))
AND LONGITUDE <= mylng +(mydst/(69 * COS(RADIANS(mylat))))
Для этого вам определенно нужен указатель в столбце LATITUDE. Индекс вашего столбца LONGITUDE также поможет немного. Он выполняет приблизительный поиск, ища строки, находящиеся внутри квази-прямоугольного патча на поверхности земли рядом с вашей точкой. Он выбирает слишком много городов, но не слишком много.
Это положение здесь позволяет исключить дополнительные города из набора результатов:
WHERE distance <= mydst
Этот раздел является формула гаверсинуса, которая вычисляет расстояние по дуге большого круга между каждым городом и точкой.
(3959 * ACOS(COS(RADIANS(LATITUDE))
* COS(RADIANS(mylat))
* COS(RADIANS(LONGITUDE) - RADIANS(mylng))
+ SIN(RADIANS(LATITUDE))
* SIN(RADIANS(mylat))
Это предложение позволяет вводить вашу точку и ваш предел радиуса только один раз в качестве связанных переменных в ваш запрос. Это полезно, потому что различные формулы используют эти переменные несколько раз.
SELECT :LAT AS mylat,
:LONG AS mylng,
:RADIUS_LIMIT AS mydst
FROM DUAL
Остальная часть запроса просто упорядочивает вещи, поэтому вы выбираете и заказываете расстояние.
Вот более полное объяснение: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
Я продолжал делать что-то вроде этого, используя кэш .. . Я надеялся добиться лучшей производительности с Spatial ... по крайней мере, чтобы сделать сравнение, чтобы посмотреть, какой путь я должен взять:) ... Спасибо за то, что вы время –
Spatial не имеет в этом никакого магии. Поиск индекса по столбцу с плавающей точкой (широта) будет иметь одинаковую сложность. –
У этого есть некоторые магические индексы R-дерева, которые значительно отличаются от обычных (B-tree) индексов и предназначены для явного решения проблемы близости по двум измерениям. –