So richten Sie eine Lösung für die mehrdimensionale Entfernungssuche mit SQL Server-Geodatentypen ein

7

Ich habe eine vorhandene Datenbanklösung, die nicht sehr gut funktioniert. Ich suche nach mehrdimensionalen Daten mit einer traditionellen Tabellenstruktur unter Verwendung von Floats usw. Die Datenbank enthält ~ 1-2 Millionen Zeilen.

Nach einiger Suche bin ich auf die SQL Server-Geodatentypen gestoßen, bei denen Sie eine Geometrie basierend auf Point oder MultiPoint definieren können, bei der Sie mit einer Entfernung suchen können. Ich denke, dies könnte eine Lösung sein, aber ich brauche Hilfe, um in die richtige Richtung zu starten.

Meine aktuelle Tabellenstruktur lautet wie folgt: Jede Zeile enthält 2 (eventuell mehr) XYZ-Werte:

    | ID | X1  | Y1  | Z1  | X2  | Y2  | Z2  |
    | 1  | 1.1 | 2.2 | 5.1 | 1.2 | 2.1 | 4.1 |
    | 2  | 3.2 | 5.1 | 4.1 | 3.2 | 3.1 | 3.1 |
    | 3  | 4.1 | 2.3 | 6.3 | 4.2 | 4.1 | 2.1 |
    | 4  | 2.4 | 3.5 | 2.1 | 3.2 | 2.1 | 4.1 |

Ich führe eine Suche mit einer Toleranz für jeden X-, Y- und Z-Wert durch.

Also zum Beispiel:

    (pseudocode)
    declare targetXYZ1 = (4.1, 2.2, 3.1);
    declare targetXYZ2 = (2.8, 2.2, 4.2);

    declare toleranceXYZ = (2,2,2)

    Select ID from MyXYZTable tb
    Where 
           Math.Abs(tb.X1 - targetXYZ1.X1) < toleranceXYZ.X 
       AND Math.Abs(tb.Y1 - targetXYZ1.Y1) < toleranceXYZ.Y
       AND Math.Abs(tb.Z1 - targetXYZ1.Z1) < toleranceXYZ.Z

       AND Math.Abs(tb.X2 - targetXYZ1.X2) < toleranceXYZ.X 
       AND Math.Abs(tb.Y2 - targetXYZ1.Y2) < toleranceXYZ.Y
       AND Math.Abs(tb.Z2 - targetXYZ1.Z2) < toleranceXYZ.Z

Nach einiger Analyse müsste ich wahrscheinlich eine Tabelle mit 1 oder 2 Geometriespalten für xyz1 und xyz2 mit Geometrie :: Punkt (0, 0, 0) erstellen.

Meine Fragen:

  1. Ist mit räumlichen SQL Server-Typen eine Lösung möglich?
  2. Muss ich die Suche nach dem nächsten Nachbarn verwenden oder kann ich STDistance verwenden?
  3. Muss ich einen räumlichen Index für die Tabelle einrichten?

Ratschläge oder Tipps und Tricks sind herzlich willkommen!

wilkokosten
quelle

Antworten:

5

Es mag einige räumliche Methoden geben, die bis zu einem gewissen Grad nützlich sind, aber Ihr größtes Problem wird der Z-Wert sein :

Z-Koordinaten werden in keiner von der Bibliothek durchgeführten Berechnung verwendet und werden nicht durch Bibliotheksberechnungen geführt.

Dies ist beabsichtigt. Stellen Sie sich räumliche SQL-Objekte nicht als "echte" 3D-geometrische Objekte vor, sondern als Kartenkoordinaten mit einem "Höhen-Tag", das bei keiner Berechnung berücksichtigt wird. Die Entfernungsfunktion eignet sich also STDistance()hervorragend für "Kartenentfernungen", jedoch nicht für echte 3D-Entfernungen.

Sie definieren den Z - Wert (und den „M“ -Wert) von einem Punkt, aber es wird nicht durch Berechnungen verwendet.

Demonstrieren:

DECLARE @a geometry = geometry::Parse('POINT(0 0 0 2)');
DECLARE @b geometry = geometry::Parse('POINT(1 0 5 1)');
SELECT @a.Z, @b.Z, @a.STDistance(@b)

gibt die Werte zurück

0   5   1

Der Abstand zwischen diesen beiden Punkten sollte eindeutig mehr als 1 betragen, wenn das Z richtig verwendet wird. Sie funktionieren also möglicherweise nicht so, wie Sie es sich erhoffen.

Wenn Sie den Z-Wert jedoch ignorieren können, ist die Durchführung dieser Berechnungen ziemlich einfach. Sie können diese Werte wie folgt aus Ihrer vorhandenen Tabelle lesen:

SELECT geometry::Point(X1,Y1,0).STDistance(geometry::Point(X2,Y2,0))
From myTable;  

(Das ist 0bei dieser Verwendung kein Z-Wert, sondern eine SRID .)

oder, wenn Sie sich die Zeit nehmen, um zu ändern, wie sie tatsächlich gespeichert sind:

CREATE TABLE myPoints (ID INT, P1 geometry, P2 geometry)

INSERT myPoints 
SELECT 1, geometry::Point(X1, Y1, 0), geometry::Point(X2, Y2, 0)
FROM oldTable

SELECT ID, P1.STDistance(P2)
FROM myPoints

In einer meiner älteren Antworten hier gibt es einige verwandte Diskussionen .

EDIT : Einige weitere Gedanken:

  1. In Bezug auf die Leistung habe ich absolut keine Ahnung, wie geometryObjekte in Bezug auf die Leistung mit der manuellen Berechnung verglichen werden. Ich kann mir vorstellen, dass die Konvertierung in Geometrieobjekte im laufenden Betrieb einen gewissen Overhead hat, aber möglicherweise ist die Konvertierung der Speicherung Ihrer Rohdaten besser. Testen wird hier der Schlüssel sein.
  2. Der Z-Parameter wird möglicherweise nicht von der STDistance()Funktion verwendet, aber Sie können ihn natürlich manuell abfragen Z und verwenden, um diesen Teil der Mathematik selbst auszuführen. Verwenden Sie einfach Pythagoras: True3D_Distance ^ 2 = STDistance ^ 2 + (aZ-bZ) ^ 2
  3. Aber beachten Sie, dass , wenn Ihr Ziel ist einfach Rang der Punkte durch die Nähe, und Sie nicht über den zur Berechnung müssen tatsächlichen Abstand, können Sie Ihre Berechnung vereinfachen. Ich denke so etwas WHERE PointA.STDistance(PointB) + ABS(PointA.Z-PointB.Z) < toleranceoder vielleichtWHERE PointA.STDistance(PointB) < tolerance AND ABS(PointA.Z-PointB.Z) < tolerance
BradC
quelle
Vielen Dank für Ihre Klarstellung. Dadurch habe ich viel Zeit gespart, um diese Technologie in SQL zu untersuchen. Ich muss mich wahrscheinlich an den mehrspaltigen (Floats) Ansatz halten :-) und eine intelligente Indizierung vornehmen, um ihn schneller zu machen. Vielen Dank!
Wilkokosten
Kein Problem, @wilkokosten, ich bin froh, dass ich helfen kann. Ich habe meinem Beitrag einige weitere Gedanken hinzugefügt. Es ist klar, dass es nicht alles oder nichts ist. Sie können möglicherweise räumliche Funktionen für einige Teile und manuelle Berechnungen für andere verwenden. Viel Glück.
BradC
0

Als Randnotiz unterstützt PostGIS 3D-Koordinaten und SRIDs (was SQL Server nicht tut). Siehe ST_3DDistance . Und es wird KNN auf einem 3D-Index mit dem <<->>Operator und ST_3DDWithin ausführen

SELECT *
FROM tbl_Foo AS t
WHERE ST_3DDWithin( t.3dgeom, mycord, distance_in_meters );
  ORDER BY t.3dgeom <<->> mycord;

^ Findet und ordnet es in einem Index.

Evan Carroll
quelle