MySQL-Guru oder nicht, das Problem ist, dass die Entfernung zwischen jedem Punkt und jeder Stadt berechnet werden muss, es sei denn, Sie finden einen Weg, verschiedene Zeilen herauszufiltern ...
Es gibt zwei allgemeine Ansätze, die der Situation helfen können
- Entfernungsformel einfacher machen
- Unwahrscheinliche Kandidaten im Umkreis von 100.000 um eine bestimmte Stadt herausfiltern
Bevor Sie sich diesen beiden Verbesserungsmöglichkeiten zuwenden, sollten Sie sich für die gewünschte Genauigkeit in Bezug auf diese 100-Meilen-Distanz entscheiden und angeben, welches geografische Gebiet von der Datenbank abgedeckt wird (ist dies nur das US-amerikanische Festland usw.).
Der Grund dafür ist, dass die Großkreisformel, obwohl sie numerisch genauer ist, sehr rechenintensiv ist. Ein weiterer Weg zur Leistungsverbesserung wäre das Speichern von "Gitterkoordinaten" zusätzlich (oder anstelle von) den Lat/Long-Koordinaten.
Bearbeiten :
Ein paar Ideen zu einer einfacheren (aber weniger genauen) Formel :
Da wir es mit relativ kleinen Entfernungen zu tun haben (und ich schätze zwischen 30 und 48 Grad Breite Nord), können wir die euklidische Entfernung (oder besser noch das Quadrat der euklidischen Entfernung) anstelle der verwenden kompliziertere Formeln der sphärischen Trigonometrie.
Abhängig von der erwarteten Genauigkeit kann es sogar akzeptabel sein, einen einzigen Parameter für die lineare Entfernung für einen vollen Längengrad zu haben, wobei etwas Mittelwert über den betrachteten Bereich genommen wird (sagen wir etwa 46 Satzung Meilen). Die Formel würde dann zu
LatDegInMi = 69.0
LongDegInMi = 46.0
DistSquared = ((Lat1 - Lat2) * LatDegInMi) ^2 + ((Long1 - Long2) * LongDegInMi) ^2
Über die Idee einer Spalte mit Rasterinformationen zum Filtern, um die Anzahl der Zeilen zu begrenzen wird für die Entfernungsberechnung berücksichtigt.
Jedem "Punkt" im System, sei es eine Stadt oder ein anderer Punkt (?Lieferorte, Geschäftsstandorte ... was auch immer) werden zwei ganzzahlige Koordinaten zugewiesen, die das Quadrat von beispielsweise 25 Meilen definieren * 25 Meilen, wo der Punkt liegt. Die Koordinaten jedes Punktes innerhalb von 100 Meilen vom Referenzpunkt (einer gegebenen Stadt) betragen höchstens +/- 4 in x-Richtung und +/- 4 in y-Richtung. Wir können dann eine Abfrage ähnlich der folgenden schreiben
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;
Beachten Sie, dass LongDegInMi entweder fest codiert sein kann (für alle Standorte innerhalb der kontinentalen USA gleich) oder aus dem entsprechenden Datensatz in der Postleitzahlentabelle stammen kann. In ähnlicher Weise könnte LatDegInMi fest codiert sein (es muss kaum variiert werden, da es im Gegensatz zu den anderen relativ konstant ist).
Der Grund, warum dies schneller ist, liegt darin, dass wir für die meisten Datensätze im kartesischen Produkt zwischen der Postleitzahlentabelle und der Punktetabelle die Entfernung überhaupt nicht berechnen. Wir eliminieren sie anhand eines Indexwertes (GridX und GridY).
Das bringt uns zu der Frage, welche SQL-Indizes erzeugt werden sollen. Natürlich möchten wir vielleicht:- GridX + GridY + Status (auf der Punktetabelle) - GridY + GridX + Status (möglicherweise) - City + State + Breitengrad + Längengrad + GridX + GridY auf der Postleitzahlentabelle
Eine Alternative zu den Rastern besteht darin, die Grenzen der Breiten- und Längengrade zu "begrenzen", die wir auf der Grundlage der Breiten- und Längengrade einer bestimmten Stadt berücksichtigen werden. d.h. die JOIN-Bedingung wird zu einem Bereich und nicht zu einem 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))