Hallo Markus*,
Prinzipiell muss man dazu natürlich jeden Punkt mit jedem vergleichen, was zu von Dir schon festgestellten quadratischen Komplexität führt. Im allgemeinen Fall kann man daran nichts ändern, allerdings gelten vermutlich zwei Dinge, die das etwas einfacher machen sollten:
Die Punkte sind mehr oder weniger gleichmäßig über eine große (quadratische) Fläche verteilt und der Umkreis (oder vielmehr das Umquadrat) ist relativ dazu klein.
Im Folgenden nehmen wir mal an, die Gesamtfläche und die Umkreisfläche seien Quadrate.
Wenn wir nun irgend eine Teilfläche betrachten und dafür jeweils die Punkte im Umkreis betrachten wollen, so müssen wir nur die Punkte auf der Teilfläche mit allen Punkten vergleichen, die höchstens so weit von der Teilfläche wegliegen, wie der Umgebungsabstand angibt.
Wir nutzen quasi aus, dass Punkte, die viel zu weit weg von unserer Teilfläche sind, erst gar nicht in Frage für die Umgebung eines Punktes auf der Teilfläche kommen.
Wählen wir unsere Teilfläche gleich der Gesammtfläche, gewinnen wir natürlich nichts, wählen wir sie so, dass gerade ein Punkt drauf liegt, gewinnen wir auch nichts, aber irgendwo dazwischen könnten wir mit weniger Vergleichen durchkommen.
Betrachten wir also zunächst die Komplexität dieses Algorithmus:
n: Anzahl der Punkte
s: Seitenlänge der Gesamtfläche
d: Umgebungsseitenlänge
l: Seitenlänge einer Teilfläche
x = (s / l)²: Anzal der Teilflächen, die auf die Gesammtfläche passen.
y = (s / d)²: Anzahl der Umgebungsflächen, die auf die Gesammtfläche passen.
Für jede Teilfläche müssen wir die Punkte darauf vergleichen: n²/x² - n/x Schritte
Für jede Teilfläche müssen wir die Punkte mit den Punkten der angrenzenden acht Umgebungsflächen vergleichen: 8 * n/x * n/y
Für jede Teilfläche müssen wir die Punkte darauf bestimmen: n Schritte
Für die Komplexität ergibt sich also:
f(n) = (8 * n/x * n/y + n²/x² - n/x + n) * x = 8 * n²/y + n²/x - n + n*x
Nun müssen wir bestimmen, welches l bzw x optimal ist (mittels der Ableitung von f(n) nach x):
df/dx (n) = - n²/x² + n = 0
n*x² = n²
x² = n
x = n^(1/2)
somit:
(s/l)² = n^(1/2)
s/l = n^(1/4)
l = s / n^(1/4)
Nun haben wir das optimale x bzw. l und können das in f(n) einsetzen:
g(n) = 8 * n²/y + n²/n^(1/2) - n + n * n^(1/2) = 8 * n² / y - n
Nun haben wir die Komplexität, wenn wir die Teilflächen optimal wählen.
Wie man sieht, kann ein großes y bzw. kleines d die Anzahl der Schritte verringern. Jetzt müssen wir natürlich noch wissen, wie klein d sein muss, damit dieser Algorithmus besser ist, als der naive Ansatz:
8 * n² / y - n < n² - n
8 * d² / s² < 1
d² < s²/8
d < s/8^(1/2) ~= 0.35*s
Wenn also der Abstand kleiner als 1/3 der Gesamtseitenlänge ist, ist unser neuer Algorithmus besser.
Bleibt noch die Frage, wie man das elegant in SQL realisiert.
Die einfachste Variante ist sicher, für jede Teilfläche ein Query durchzuführen (sinnvollerweise mit einem Perpared Statement oder als Stored Procedure).
Was in den Betrachtungen noch nicht eingeflossen ist, sind DB-Indexe.
Wenn der Verwendete Index das schnelle Selektieren nach Koordinatenbereichen ermöglich, als beispielsweise in logarithmischer Zeit, sollte schon der naive Ansatz relativ gut sein und diese Variante bringt nicht mehr viel (müsste man analysieren).
Ich weiß auch nicht, wie schlau Dein DBMS in Deinem Fall ist und ob es tatsächlich zunächst die komplette JOIN-Tabelle aufbaut. Evtl. bringt es schon was, die Bedinung als JOIN-Bedingung unterzubringen.
Grüße
Daniel