Mysql
 sql >> Database >  >> RDS >> Mysql

Query SQL per punti totali entro il raggio di una posizione

MySQL Guru o meno, il problema è che, a meno che non trovi un modo per filtrare le varie righe, la distanza deve essere calcolata tra ogni punto e ogni città...

Ci sono due approcci generali che possono aiutare la situazione

  • Semplifica la formula della distanza
  • Filtra i candidati improbabili nel raggio di 100.000 da una determinata città

Prima di entrare in queste due vie di miglioramento, dovresti decidere il livello di precisione desiderato rispetto a questa distanza di 100 miglia, inoltre dovresti indicare quale area geografica è coperta dal database (sono solo USA continentali ecc.

La ragione di ciò è che, sebbene numericamente più precisa, la formula del Great Circle è molto costosa dal punto di vista computazionale. Un'altra via di miglioramento delle prestazioni sarebbe quella di memorizzare "coordinate griglia" di sorta in aggiunta (o al posto delle) coordinate Lat/Long.

Modifica :
Alcune idee su una formula più semplice (ma meno precisa) :
Dato che abbiamo a che fare con distanze relativamente piccole, (e suppongo tra 30 e 48 gradi Lat North), possiamo usare la distanza euclidea (o meglio ancora il quadrato della distanza euclidea) piuttosto che la formule di trigonometria sferica più complicate.
a seconda del livello di precisione previsto, può anche essere accettabile avere un singolo parametro per la distanza lineare per un intero grado di longitudine, prendendo qualcosa di medio sull'area considerata (diciamo circa 46 statuto miglia). La formula diventerebbe quindi

  LatDegInMi = 69.0
  LongDegInMi = 46.0
  DistSquared = ((Lat1 - Lat2) * LatDegInMi) ^2 + ((Long1 - Long2) * LongDegInMi) ^2

Sull'idea di una colonna con informazioni griglia da filtrare per limitare il numero di righe considerato per il calcolo della distanza.
A ogni "punto" nel sistema, che si tratti di una città o di un altro punto (?Località di consegna, posizioni dei negozi... qualunque cosa) vengono assegnate due coordinate intere che definiscono il quadrato di diciamo 25 miglia * 25 miglia dove si trova il punto. Le coordinate di qualsiasi punto entro 100 miglia dal punto di riferimento (una determinata città), saranno al massimo +/- 4 nella direzione x e +/- 4 nella direzione y. Possiamo quindi scrivere una query simile alla seguente

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;

Nota che il LongDegInMi potrebbe essere codificato (lo stesso per tutte le località all'interno degli Stati Uniti continentali) o provenire dal record corrispondente nella tabella dei codici postali. Allo stesso modo, LatDegInMi potrebbe essere hardcoded (non c'è bisogno di farlo variare, poiché a differenza dell'altro è relativamente costante).

Il motivo per cui questo è più veloce è che per la maggior parte dei record nel prodotto cartesiano tra la tabella dei codici postali e la tabella dei punti, non calcoliamo affatto la distanza. Li eliminiamo sulla base di un valore di indice (GridX e GridY).

Questo ci porta alla domanda su quali indici SQL produrre. Di sicuro, potremmo volere:- GridX + GridY + Status (sulla tabella dei punti)- GridY + GridX + stato (possibilmente)- Città + Stato + latitudine + longitudine + GridX + GridY sulla tabella dei codici postali

Un'alternativa alle griglie è quella di "limitare" i limiti di latitudine e longitudine che prenderemo in considerazione, in base alla latitudine e longitudine di una data città. cioè la condizione JOIN diventa un intervallo piuttosto che un 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))