Ottimizza la query sul vicino più vicino su 70 milioni di nuvole di punti su SQL Server 2008


16

Ho circa 75 milioni di record in un database di SQL Server 2008 R2 Express. Ciascuno è un lat long corrispondente ad un certo valore. La tabella ha una colonna geografica. Sto cercando di trovare un vicino più vicino per una determinata latitudine (punto). Ho già una query con l'indice spaziale in atto. Ma a seconda di dove si trova il record nel database, ad esempio il primo o l'ultimo trimestre, la query può richiedere da 3 a 30 secondi per trovare il vicino più vicino. Penso che questo possa essere ottimizzato per dare risultati molto più veloci ottimizzando la query o l'indice spaziale. In questo momento ha applicato un po 'l'indice spaziale con le impostazioni predefinite. Ecco come sono la mia tabella e query.

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]

L'indice spaziale che sto usando:

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]

Ecco la query che sto usando:

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

Ecco un esempio di long long nel mio database. per dare un'idea di precisione e densità. Tutti i 70 milioni di record sono per una città (dati Lidar).

POINT (-95.669434934023087 30.049513838913736)

Ora questa query mi dà risultati come ho descritto sopra, ma voglio migliorare le prestazioni il più possibile. La mia ipotesi è che modificando i valori predefiniti dell'indice spaziale che posso essere sopra per ottimizzare meglio le prestazioni. Qualche idea su questo?

Ho provato a variare il buffer da 10 a 1000 ma con quasi gli stessi risultati.

Anche qualsiasi altro suggerimento per migliorare le prestazioni è il benvenuto.

Ecco il sistema che sto usando in questo momento:

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

1
Sono dati lidar? In tal caso, aggiungi un lidartag.
Kirk Kuykendall l'

2
Non parlo di SQL Server, ma mi sembra che la tua query non trovi tutti i punti che si trovano all'interno di un buffer di 1000 metri dal punto di destinazione. Questi test point-in-poligoni saranno molto più lenti dei test di prossimità, che sono la base per le soluzioni offerte nella domanda precedente .
whuber

@whuber: ho provato le query basate sulla distanza e il tempo in minuti. fino in alto. Forse sto sbagliando da qualche parte. A partire da questi punti nel poligono, ci vuole tempo in secondi. Anche la variazione del buffer da 10 a 10000 ha poco impatto sul tempo.
Shaunak,

1
@Shaunak Poi c'è qualcosa che non va nelle query basate sulla distanza, perché teoricamente possono essere eseguite in media in microsecondi (o meglio) e in millisecondi (caso peggiore) usando indici appropriati come gli alberi KD . Potresti voler pensare a migliorarli piuttosto che cercare modi per ottimizzare la ricerca point-in-buffer.
whuber

Sono questi i dati della griglia? Perché non usare un raster?
Matthew Snape,

Risposte:


9

Prova a eseguire la procedura memorizzata sp_help_spatial_geography_index per ottenere dettagli sull'utilizzo dell'indice spaziale. Dovresti essere in grado di usare qualcosa come:

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;

Pubblica i risultati nella tua domanda per vedere se qualcosa si distingue. Il significato di ciascuno degli articoli è disponibile qui .

Se le tue coordinate sono state proiettate, puoi anche eseguire una semplice query non spaziale sui campi X, Y calcolati e controllare X <MinX e X> MaxX ecc.

La proiezione delle coordinate (in un campo di tipo GEOMETRIA) consente inoltre di limitare l'indice spaziale nella misura in cui i dati possono accelerare notevolmente le prestazioni. Sostituisci le estensioni del mondo con le estensioni dei tuoi dati:

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]

1
Secondo technet.microsoft.com/en-us/library/bb934196.aspx il BOUNDING_BOX può essere utilizzato solo per GEOMETRY_GRID, non GEOGRAPHY_GRID
Kelso,

1
Risposta aggiornata. Il tipo GEOMETRY dovrebbe essere molto più veloce in quanto è possibile impostare BOUNDING_BOX.
geographika,

1

Prendi in considerazione la semplificazione del buffer con BufferwithTolerance . Se i punti sono strettamente imballati, il sistema deve identificare se un punto è uno dei due lati del confine. Più semplice è quella linea, meno lavoro deve fare la macchina.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.