Optimieren Sie die Abfrage des nächsten Nachbarn in einer 70-Millionen-Punkt-Cloud unter SQL Server 2008

16

Ich habe ungefähr 75 Millionen Datensätze in einer SQL Server 2008 R2 Express-Datenbank. Jedes ist eine Lat-Länge, die einem bestimmten Wert entspricht. Die Tabelle enthält die Spalte "Geografie". Ich versuche, einen nächsten Nachbarn für einen bestimmten Längengrad (Punkt) zu finden. Ich habe bereits eine Abfrage mit räumlichem Index. Abhängig davon, wo sich der Datensatz in der Datenbank befindet, beispielsweise im ersten oder letzten Quartal, kann die Abfrage 3 bis 30 Sekunden dauern, bis der nächste Nachbar gefunden ist. Ich bin der Meinung, dass dies optimiert werden kann, um viel schnellere Ergebnisse zu erzielen, indem die Abfrage oder der räumliche Index optimiert werden. Im Moment haben einige den räumlichen Index mit den Standardeinstellungen angewendet. So sieht meine Tabelle und Abfrage aus.

CREATE TABLE lidar(
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [POINTID] [int] NOT NULL,
    [GRID_CODE] [numeric](17, 8) NULL,
    [geom] [geography] NULL,
 CONSTRAINT [PK_lidar_1] PRIMARY KEY CLUSTERED ([id] ASC)
 WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
 ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Der von mir verwendete räumliche Index:

CREATE SPATIAL INDEX [SPATIAL_lidar] ON [dbo].[lidar] ([geom]) USING  GEOGRAPHY_GRID 
WITH (
GRIDS =(LEVEL_1 = MEDIUM,LEVEL_2 = MEDIUM,LEVEL_3 = MEDIUM,LEVEL_4 = MEDIUM), 
CELLS_PER_OBJECT = 16, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,  
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Hier ist die Abfrage, die ich verwende:

declare @ms_at geography = 'POINT (-95.66 30.04)';
select TOP(1) nearPoints.geom.STAsText()as latlon 
from
(
select r.geom
from lidar r With(Index(SPATIAL_lidar))
where r.geom.STIntersects(@ms_at.STBuffer(1000)) = 1
) nearPoints

Hier ist ein Beispiel für Lat Longs in meiner Datenbank. um eine Vorstellung von Genauigkeit und Dichte zu geben. Alle 70 Millionen Datensätze beziehen sich auf eine Stadt (Lidar-Daten).

POINT (-95.669434934023087 30.049513838913736)

Mit dieser Abfrage erhalte ich nun die oben beschriebenen Ergebnisse, aber ich möchte die Leistung so weit wie möglich verbessern. Meine Vermutung ist, dass ich die Standardwerte des räumlichen Indexes, über dem ich möglicherweise bin, optimiere, um die Leistung besser zu optimieren. Irgendwelche Hinweise dazu?

Ich habe versucht, den Puffer von 10 auf 1000 zu variieren, aber mit fast den gleichen Ergebnissen.

Auch alle anderen Vorschläge zur Verbesserung der Leistung sind willkommen.

Hier ist das System, das ich gerade benutze:

Windows 7 64bit Professional
Intel(R) Core(TM)2 Quad CPU    Q9650  @ 3.00GHz (4 CPUs), ~3.0GHz
Ram: 8 GB
NVIDIA GeForce 9500 GT
Shaunak
quelle
1
Handelt es sich um LIDAR-Daten? In diesem Fall sollten Sie ein lidarTag hinzufügen .
Kirk Kuykendall
2
Ich spreche nicht SQL Server, aber für mich sieht es so aus, als müsste Ihre Abfrage alle Punkte finden, die innerhalb eines 1000-Meter-Puffers des Zielpunkts liegen. Diese Point-in-Polygon-Tests sind viel langsamer als Proximity-Tests, die die Grundlage für die in Ihrer vorherigen Frage angebotenen Lösungen bilden .
whuber
@whuber: Ich habe es mit entfernungsbasierten Abfragen versucht und die Zeit in Minuten angegeben. viel zu hoch. Vielleicht gehe ich irgendwo falsch. Ab diesem Punkt im Polygon dauert es einige Sekunden. Selbst wenn der Puffer von 10 auf 10000 geändert wird, hat dies nur geringe Auswirkungen auf die Zeit.
Shaunak
1
@Shaunak Dann ist bei den entfernungsbasierten Abfragen etwas los, denn theoretisch können sie mit geeigneten Indizes wie KD-Bäumen im Durchschnitt in Mikrosekunden (oder besser) und in Millisekunden (im schlimmsten Fall) ausgeführt werden . Möglicherweise möchten Sie diese verbessern, anstatt nach Möglichkeiten zu suchen, um die Point-in-Buffer-Suche zu optimieren.
whuber
Sind das Gitterdaten? Warum nicht ein Raster verwenden?
Matthew Snape

Antworten:

9

Führen Sie die gespeicherte Prozedur sp_help_spatial_geography_index aus , um Details zur Verwendung Ihres räumlichen Index abzurufen . Sie sollten in der Lage sein, Folgendes zu verwenden:

declare @ms_at geography = 'POINT (-95.66 30.04)'
set @ms_at = @ms_at.STBuffer(1000).STAsText()
exec sp_help_spatial_geography_index 'lidar', 'SPATIAL_lidar', 0, @ms_at;

Veröffentlichen Sie die Ergebnisse in Ihrer Frage, um festzustellen, ob etwas auffällt. Die Bedeutung der einzelnen Elemente finden Sie hier .

Wenn Ihre Koordinaten projiziert wurden, können Sie auch eine einfache nicht-räumliche Abfrage für berechnete X-, Y-Felder durchführen und X <MinX und X> MaxX usw. überprüfen.

Durch Projizieren Ihrer Koordinaten (in ein GEOMETRIE-Feld) können Sie auch Ihren räumlichen Index auf den Umfang der Daten beschränken, wodurch die Leistung erheblich gesteigert werden kann. Ersetzen Sie die Weltbereiche durch die Bereiche Ihrer Daten:

CREATE SPATIAL INDEX [SPATIAL_lidar] ON [dbo].[lidar] ([geom]) USING  GEOMETRY_GRID 
WITH (
GRIDS =(LEVEL_1 = MEDIUM,LEVEL_2 = MEDIUM,LEVEL_3 = MEDIUM,LEVEL_4 = MEDIUM), 
CELLS_PER_OBJECT = 16, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,  
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON,
BOUNDING_BOX =(-90, -180, 90, 180),) ON [PRIMARY]
geographika
quelle
1
Laut technet.microsoft.com/en-us/library/bb934196.aspx kann die BOUNDING_BOX nur für GEOMETRY_GRID verwendet werden, nicht für GEOGRAPHY_GRID
Kelso
1
Aktualisierte Antwort. Der GEOMETRY-Typ sollte viel schneller sein, da die BOUNDING_BOX gesetzt werden kann.
Geographika
1

Vereinfachen Sie den Puffer mit BufferwithTolerance . Wenn Punkte dicht gepackt sind, muss das System feststellen, ob sich ein Punkt auf einer Seite der Grenze befindet. Je einfacher diese Linie ist, desto weniger Arbeit muss die Maschine leisten.

Matthew Snape
quelle