Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Entfernungsberechnung mit riesiger SQL Server Datenbank

Sie könnten Schlimmeres tun, als sich die GEOGRAPHY anzusehen Datentyp, zum Beispiel:

CREATE TABLE Places
(
    SeqID       INT IDENTITY(1,1),
    Place       NVARCHAR(20),
    Location    GEOGRAPHY
)
GO
INSERT INTO Places (Place, Location) VALUES ('Coventry', geography::Point(52.4167, -1.55, 4326))
INSERT INTO Places (Place, Location) VALUES ('Sheffield', geography::Point(53.3667, -1.5, 4326))
INSERT INTO Places (Place, Location) VALUES ('Penzance', geography::Point(50.1214, -5.5347, 4326))
INSERT INTO Places (Place, Location) VALUES ('Brentwood', geography::Point(52.6208, 0.3033, 4326))
INSERT INTO Places (Place, Location) VALUES ('Inverness', geography::Point(57.4760, -4.2254, 4326))
GO
SELECT p1.Place, p2.place, p1.location.STDistance(p2.location) / 1000 AS DistanceInKilometres
    FROM Places p1
    CROSS JOIN Places p2
GO  
SELECT p1.Place, p2.place, p1.location.STDistance(p2.location) / 1000 AS DistanceInKilometres
    FROM Places p1
        INNER JOIN Places p2 ON p1.SeqID > p2.SeqID
GO  

geography::Point nimmt den Breiten- und Längengrad sowie eine SRID (Special Reference ID number). In diesem Fall ist die SRID 4326, was dem Standard-Breiten- und -Längengrad entspricht. Da Sie bereits Längen- und Breitengrad haben, können Sie einfach ALTER TABLE Um die geografische Spalte hinzuzufügen, dann UPDATE zu füllen.

Ich habe zwei Möglichkeiten gezeigt, um die Daten aus der Tabelle zu bekommen, aber Sie können damit keine indizierte Ansicht erstellen (indizierte Ansichten können keine Selbstverknüpfungen haben). Sie könnten jedoch eine sekundäre Tabelle erstellen, die effektiv ein Cache ist, der basierend auf dem oben Gesagten gefüllt wird. Sie müssen sich dann nur um die Wartung kümmern (könnte durch Trigger oder einen anderen Prozess erfolgen).

Beachten Sie, dass der Cross Join Ihnen 250.000.000.000 Zeilen liefert, aber die Suche ist einfach, da Sie nur eine der Ortsspalten betrachten müssen (d. h. SELECT * FROM table WHERE Place1 = 'Sheffield' AND distance < 100 , die zweite gibt Ihnen deutlich weniger Zeilen, aber die Abfrage muss dann sowohl die Spalte Place1 als auch Place2 berücksichtigen).