sql >> Database >  >> RDS >> Mysql

SQL-query voor totaal aantal punten binnen de straal van een locatie

MySQL-goeroe of niet, het probleem is dat, tenzij je een manier vindt om verschillende rijen uit te filteren, de afstand tussen elk punt en elke stad moet worden berekend...

Er zijn twee algemene benaderingen die de situatie kunnen helpen

  • maak de afstandsformule eenvoudiger
  • filter onwaarschijnlijke kandidaten uit de 100k straal van een bepaalde stad

Voordat u op deze twee manieren van verbetering ingaat, moet u beslissen over het gewenste precisieniveau met betrekking tot deze afstand van 100 mijl, en u moet ook aangeven welk geografisch gebied door de database wordt bestreken (is dit gewoon de continentale VS enz.

De reden hiervoor is dat, hoewel numeriek nauwkeuriger, de formule van de Grote Cirkel, erg rekenkundig duur is. Een andere manier om de prestaties te verbeteren zou zijn om "Grid-coördinaten" op te slaan naast (of in plaats van) de Lat/Long-coördinaten.

Bewerken :
Enkele ideeën over een eenvoudigere (maar minder nauwkeurige) formule :
Omdat we te maken hebben met relatief kleine afstanden (en ik gok tussen 30 en 48 graden noorderbreedte), kunnen we de euclidische afstand (of beter nog het kwadraat van de euclidische afstand) gebruiken in plaats van de meer gecompliceerde formules voor sferische trigonometrie.
Afhankelijk van het verwachte precisieniveau, kan het zelfs acceptabel zijn om één enkele parameter voor de lineaire afstand te hebben voor een volledige lengtegraad, waarbij we iets gemiddelds nemen over het beschouwde gebied (zeg circa 46 statuut mijl). De formule wordt dan

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

Op het idee van kolommen met rasterinfo om te filteren om het aantal rijen te beperken beschouwd voor afstandsberekening.
Aan elk "punt" in het systeem, of het nu een stad is of een ander punt (afleverlocaties, winkellocaties... wat dan ook) wordt twee integere coördinaten toegewezen die het kwadraat van bijvoorbeeld 25 mijl definiëren * 25 mijl waar het punt ligt. De coördinaten van elk punt binnen een straal van 100 mijl van het referentiepunt (een bepaalde stad), zijn maximaal +/- 4 in de x-richting en +/- 4 in de y-richting. We kunnen dan een query schrijven die lijkt op de volgende

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;

Merk op dat de LongDegInMi ofwel hardgecodeerd kan zijn (hetzelfde voor alle locaties binnen de continentale VS), of afkomstig kan zijn van een overeenkomstig record in de postcodetabel. Op dezelfde manier kan LatDegInMi hardcoded zijn (het is weinig nodig om het te laten variëren, omdat het, in tegenstelling tot de andere, relatief constant is).

De reden waarom dit sneller is, is dat we voor de meeste records in het cartesiaanse product tussen de postcodetabel en de puntentabel de afstand helemaal niet berekenen. We elimineren ze op basis van een indexwaarde (de GridX en GridY).

Dit brengt ons bij de vraag welke SQL-indexen we moeten produceren. We willen zeker:- GridX + GridY + Status (op de puntentabel) - GridY + GridX + status (mogelijk) - Stad + Staat + breedtegraad + lengtegraad + GridX + GridY op de postcodetabel

Een alternatief voor de rasters is om de limieten van de breedte- en lengtegraad te "begrenzen", die we zullen beschouwen, op basis van de breedte- en lengtegraad van een bepaalde stad. d.w.z. de JOIN-voorwaarde wordt een bereik in plaats van een 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)) 


  1. Oracle-certificeringen

  2. Bulk Sql Server invoegen miljoenen records

  3. Zoeken met jokertekens in MySQL full-text zoeken

  4. Dubbelzinnige kolomnaamfout op een bepaalde server