Ich erstelle eine Datenbank, die auf einem MS SQL 2012-Server gehostet wird. Die Hauptfunktion dieser Datenbank besteht darin, Ergebnisse zurückzugeben, die sich in einer bestimmten Entfernung von einem Ursprung befinden. Standorte werden als Breiten-/Längengrad gespeichert.Optimieren von SQL WHERE zum Berechnen der Entfernung zwischen Längen- und Breitenpositionen
Indem ich hier auf Stack Overflow gelesen habe, habe ich eine sehr gute Möglichkeit gefunden, die Datenbank genau nach dem zu durchsuchen, wonach ich suche, und es funktioniert wie ein Zauber! Ich denke jedoch über einen möglichen Weg nach, dies zu optimieren.
Original-SQL-Abfrage
DECLARE @orig_lat DECIMAL(12, 9)
DECLARE @orig_lng DECIMAL(12, 9)
SET @orig_lat=56.xxxxxx
SET @orig_lng=14.xxxxxx
DECLARE @orig geography = geography::Point(@orig_lat, @orig_lng, 4326);
SELECT *
FROM foobar
WHERE @orig.STDistance(geography::Point(foobar.latitude, foobar.longitude, 4326)) < 2000
Meine Vermutung ist, dass diese Abfrage hat eine lineare Suche der foobar Tabelle nur die passenden Spalten zurück. Da diese Tabelle jedoch Positionen auf der ganzen Welt enthält, möchte ich wissen, ob ich der Datenbank helfen kann, indem ich die Anzahl der Zeilen reduziere, auf denen die Entfernungsberechnung ausgeführt werden soll. Meine Vermutung ist, dass diese Berechnung für den Server schwer ist.
Ich weiß, woher die Anfrage stammt, und ich weiß auch, dass die maximale Entfernung zwischen den Punkten niemals größer als etwa 100km sein wird.
Hypothese
Da ich weiß, dass ich bis zu 100 km von Entstehungsort nicht nur die ganze Welt suchen muss ich auf die WHERE-Anweisung verbessern, wie unten zu sehen. Durch Erstellen einer Mindest- und Höchstgrenze für den Breiten- und Längengrad, die durch Verschieben der Position um eine Zahl in jeder Richtung erreicht wird.
ich erklären:
- Herkunft Breite 56.xxxxxx
- Min Breite 55.xxxxxx
Max Breite 57.xxxxxx
Herkunft Länge 14.xxxxxx
- Min Längengrad 13.xxxxxx
- Max Längengrad 15.xxxx xx
Dadurch erstelle ich eine Zone um den Ursprung, die ungefähr 126km erreicht. Indem ich dies der WHERE-Anweisung hinzufüge, stelle ich zuerst sicher, dass die angeforderte Position innerhalb der korrekten Grenzen liegt. Danach führe ich die Entfernungsberechnung durch, um die exakte Entfernung zu erhalten. Die Entfernungsberechnung wird jetzt nur noch gegen die Zeilen ausgeführt, die innerhalb der Min- und Max-Grenzen statt der ganzen Welt liegen.
Optimierungsvorschlag
DECLARE @orig_lat DECIMAL(12, 9)
DECLARE @orig_lng DECIMAL(12, 9)
DECLARE @orig_latMin DECIMAL(12, 9)
DECLARE @orig_latMax DECIMAL(12, 9)
DECLARE @orig_lngMin DECIMAL(12, 9)
DECLARE @orig_lngMax DECIMAL(12, 9)
SET @orig_lat=56.xxxxxx
SET @orig_lng=14.xxxxxx
SET @orig_latMin=55.xxxxxx
SET @orig_latMax=57.xxxxxx
SET @orig_lngMin=13.xxxxxx
SET @orig_lngMax=15.xxxxxx
DECLARE @orig geography = geography::Point(@orig_lat, @orig_lng, 4326);
SELECT *
FROM foobar
WHERE ([latitude] > @orig_latMin
AND [latitude] < @orig_latMax
AND [longitude] > @orig_lngMin
AND [longitude] < @orig_lngMax)
AND @orig.STDistance(geography::Point(foobar.latitude, foobar.longitude, 4326)) < 2000
Ich weiß Details nicht Datenbank-Implementierung aber bedeutet dies die Abfrage verbessern oder sie es nicht noch schlimmer machen? Meine Vermutung ist, dass es darauf ankommt, wie die WHERE-Anweisung tatsächlich funktioniert und in welcher Reihenfolge sie Dinge dosiert. Meine Hoffnung ist, dass die Grenzkontrollen vor der Abstandsberechnung ausgeführt werden, um die Zeit zu reduzieren, die eine Abstandsberechnung durchgeführt wird.
EDIT
implementiert einfach den vorgeschlagenen Index Vorschlag mit den folgenden Ergebnissen.
ohne Indizierung:
Mit optimierten Aussage haben Kosten in Höhe von 0,025352
Ohne optimierte Aussage haben Kosten in Höhe von 0,025323
Mit Indexierung:
Mit optimierten Aussage haben Kosten in Höhe von 0,0104057
Ohne optimierte Aussage haben Kosten in Höhe von 0,0253234
Überprüfen Sie den Ausführungsplan –