Optimiser la requête de voisin le plus proche sur un nuage de 70 millions de points sur SQL Server 2008

16

J'ai environ 75 millions d'enregistrements dans une base de données SQL Server 2008 R2 Express. Chacun est un lat long correspondant à une certaine valeur. Le tableau a une colonne géographique. J'essaie de trouver un voisin le plus proche pour une longitude (point) de latitude donnée. J'ai déjà une requête avec index spatial en place. Mais selon l'endroit où l'enregistrement se trouve dans la base de données, par exemple au premier trimestre ou au dernier trimestre, la requête peut prendre environ 3 à 30 secondes pour trouver le voisin le plus proche. Je pense que cela peut être optimisé pour donner un résultat beaucoup plus rapide en optimisant la requête ou l'index spatial. À l'heure actuelle appliqué certains index spatial avec les paramètres par défaut. Voici à quoi ressemble ma table et ma requête.

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'index spatial que j'utilise:

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]

Voici la requête que j'utilise:

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

Voici un échantillon de lat longs dans ma base de données. pour donner une idée de la précision et de la densité. Tous les 70 millions d'enregistrements concernent une seule ville (données Lidar).

POINT (-95.669434934023087 30.049513838913736)

Maintenant, cette requête me donne des résultats comme je l'ai décrit ci-dessus, mais je veux améliorer les performances autant que possible. Je suppose qu'en ajustant les valeurs par défaut de l'indice spatial, je peux être au-dessus pour mieux optimiser les performances. Des indices à ce sujet?

J'ai essayé de faire varier le tampon de 10 à 1000 mais avec presque les mêmes résultats.

Toutes autres suggestions pour améliorer les performances sont également les bienvenues.

Voici le système que j'utilise actuellement:

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
la source
1
S'agit-il de données lidar? Si c'est le cas, pensez à ajouter une lidarbalise.
Kirk Kuykendall
2
Je ne parle pas de SQL Server, mais il me semble que votre requête doit trouver tous les points situés dans un tampon de 1000 mètres du point cible. Ces tests ponctuels vont être beaucoup plus lents que les tests de proximité, qui sont la base des solutions proposées dans votre question précédente .
whuber
@whuber: J'ai essayé les requêtes basées sur la distance et le temps en minutes. chemin vers le haut. Peut-être que je me trompe quelque part. À partir de ces points dans le polygone, cela prend du temps en secondes. Même la variation du tampon de 10 à 10000 a peu d'incidence sur le temps.
Shaunak
1
@Shaunak Ensuite, il y a un problème avec les requêtes basées sur la distance, car théoriquement, elles peuvent être effectuées en moyenne en microsecondes (ou mieux) et en millisecondes (pire cas) en utilisant des index appropriés tels que les arbres KD . Vous voudrez peut-être penser à les améliorer plutôt que de chercher des moyens d'optimiser la recherche de point dans la mémoire tampon.
whuber
S'agit-il de données de grille? Pourquoi ne pas utiliser un raster?
Matthew Snape

Réponses:

9

Essayez d'exécuter la procédure stockée sp_help_spatial_geography_index pour obtenir des détails sur la façon dont votre index spatial est utilisé. Vous devriez pouvoir utiliser quelque chose comme:

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;

Affichez les résultats dans votre question pour voir si quelque chose se démarque. La signification de chacun des éléments peut être trouvée ici .

Si vos coordonnées ont été projetées, vous pouvez également effectuer une simple requête non spatiale sur les champs X, Y calculés et vérifier X <MinX et X> MaxX, etc.

La projection de vos coordonnées (dans un champ de type GÉOMÉTRIE) vous permet également de limiter votre index spatial à l'étendue des données ce qui peut accélérer considérablement les performances. Remplacez l'étendue mondiale par l'étendue de vos données:

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
la source
1
Selon technet.microsoft.com/en-us/library/bb934196.aspx, le BOUNDING_BOX ne peut être utilisé que pour GEOMETRY_GRID, pas GEOGRAPHY_GRID
Kelso
1
Réponse mise à jour. Le type GEOMETRY devrait être beaucoup plus rapide car le BOUNDING_BOX peut être défini.
geographika
1

Envisagez de simplifier le tampon avec BufferwithTolerance . Si les points sont serrés, le système doit identifier si un point se trouve de part et d'autre de la frontière. Plus cette ligne est simple, moins la machine doit faire de travail.

Matthew Snape
la source