MySQL Guru или не, проблемът е, че освен ако не намерите начин за филтриране на различни редове, разстоянието трябва да се изчисли между всяка точка и всеки град...
Има два общи подхода, които могат да помогнат на ситуацията
- направете формулата за разстояние по-опростена
- филтрирайте малко вероятни кандидати до радиус 100k от даден град
Преди да преминете към тези два пътя за подобрение, трябва да вземете решение за желаното ниво на прецизност по отношение на това разстояние от 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))