MySQL Guru или нет, проблема в том, что, если вы не найдете способ отфильтровать различные строки, расстояние должно быть рассчитано между каждой точкой и каждым городом ...
Есть два основных подхода, которые могут помочь ситуации
- упростить формулу расстояния
- отфильтровывает маловероятных кандидатов на радиус 100к от данного города
Прежде чем перейти к этим двум направлениям совершенствования, вам следует определиться с желаемым уровнем точности в отношении этого расстояния в 100 миль, а также указать, какой географический район охватывается базой данных (это только континентальная часть США и т. Д.
Причина этого в том, что, хотя более точная численная формула Великого круга очень затратна в вычислительном отношении. Другим способом улучшения производительности было бы сохранение «координат сетки» в виде дополнения (или вместо) координат широты / долготы.
Редактировать
Несколько идей о более простой (но менее точной) формуле :
Поскольку мы имеем дело с относительно небольшими расстояниями (и я предполагаю, что между 30 и 48 градусами северной широты), мы можем использовать евклидово расстояние (или, что еще лучше, квадрат евклидового расстояния), а не более сложные формулы сферической тригонометрии. .
в зависимости от ожидаемого уровня точности, может быть даже приемлемым иметь один единственный параметр для линейного расстояния для полной степени долготы, принимая среднее значение по рассматриваемой области (скажем, около 46 статут миль). Формула тогда станет
LatDegInMi = 69.0
LongDegInMi = 46.0
DistSquared = ((Lat1 - Lat2) * LatDegInMi) ^2 + ((Long1 - Long2) * LongDegInMi) ^2
По идее столбцы с информацией сетки для фильтрации для ограничения количества строк , учитываемой для расчета расстояния.
Каждой «точке» в системе, будь то город или другая точка («места доставки», «места хранения» и т. Д.), Присваиваются две целочисленные координаты, которые определяют квадрат, скажем, 25 миль * 25 миль, где находится точка. Координаты любой точки в пределах 100 миль от контрольной точки (данного города) будут максимум +/- 4 в направлении x и +/- 4 в направлении y. Затем мы можем написать запрос, подобный следующему
SELECT city, state, latitude, longitude, COUNT(*)
FROM zipcodes Z
JOIN points P
ON P.GridX IN (
SELECT GridX - 4, GridX - 3, GridX - 2, GridX - 1, GridX, GridX +1, GridX + 2 GridX + 3, GridX +4
FROM zipcode ZX WHERE Z.id = ZX.id)
AND
P.GridY IN (
SELECT GridY - 4, GridY - 3, GridY - 2, GridY - 1, GridY, GridY +1, GridY + 2 GridY + 3, GridY +4
FROM zipcode ZY WHERE Z.id = ZY.id)
WHERE P.Status = A
AND ((Z.latitude - P.latitude) * LatDegInMi) ^2
+ ((Z.longitude - P.longitude) * LongDegInMi) ^2 < (100^2)
GROUP BY city,state,latitude,longitude;
Обратите внимание, что LongDegInMi может быть жестко задан (то же самое для всех местоположений в континентальной части США) или получен из соответствующей записи в таблице почтовых индексов. Аналогично, LatDegInMi может быть жестко закодирован (нет необходимости изменять его, поскольку в отличие от других он относительно постоянен).
Причина, по которой это происходит быстрее, заключается в том, что для большинства записей в декартовом произведении между таблицей почтовых индексов и таблицей точек мы вообще не вычисляем расстояние. Мы исключаем их на основе значения индекса (GridX и GridY).
Это подводит нас к вопросу о том, какие индексы SQL создавать. Конечно, мы можем захотеть:
- GridX + GridY + Status (в таблице очков)
- статус GridY + GridX + (возможно)
- Город + Штат + широта + долгота + GridX + GridY в таблице почтовых индексов
Альтернативой сеткам является «привязка» границ широты и долготы, которые мы рассмотрим, на основе широты и долготы данного города. то есть условие JOIN становится диапазоном, а не IN:
JOIN points P
ON P.latitude > (Z.Latitude - (100 / LatDegInMi))
AND P.latitude < (Z.Latitude + (100 / LatDegInMi))
AND P.longitude > (Z.longitude - (100 / LongDegInMi))
AND P.longitude < (Z.longitude + (100 / LongDegInMi))