Otimize a consulta ao vizinho mais próximo na nuvem de 70 milhões de pontos no SQL Server 2008

16

Eu tenho cerca de 75 milhões de registros em um banco de dados do SQL Server 2008 R2 Express. Cada um é um lat long correspondente a algum valor. A tabela possui coluna de geografia. Estou tentando encontrar um vizinho mais próximo para uma determinada longitude de latitude (ponto). Eu já tenho uma consulta com índice espacial em vigor. Mas, dependendo de onde o registro está no banco de dados, digamos o primeiro ou o último trimestre, a consulta pode levar de 3 a 30 segundos para encontrar o vizinho mais próximo. Eu sinto que isso pode ser otimizado para gerar resultados muito mais rápidos, otimizando a consulta ou o índice espacial. No momento, aplicamos alguns índices espaciais com as configurações padrão. Aqui está a aparência da minha tabela e consulta.

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]

O índice espacial que estou 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]

Aqui está a consulta que estou 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

Aqui está um exemplo de long long no meu banco de dados. para dar uma idéia de precisão e densidade. Todos os 70 milhões de registros são para uma cidade (dados Lidar).

POINT (-95.669434934023087 30.049513838913736)

Agora, essa consulta me fornece resultados como descrevi acima, mas quero melhorar o desempenho o máximo possível. Meu palpite é ajustar os valores padrão do índice espacial em que posso estar acima para otimizar melhor o desempenho. Alguma pista sobre isso?

Tentei variar o buffer de 10 para 1000, mas com quase os mesmos resultados.

Também são bem-vindas quaisquer outras sugestões para melhorar o desempenho.

Aqui está o sistema que estou usando agora:

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
fonte
1
São dados do Lidar? Se sim, considere adicionar uma lidartag.
Kirk Kuykendall 11/07
2
Não falo SQL Server, mas parece-me sem instrução que sua consulta precisa encontrar todos os pontos dentro de um buffer de 1000 metros do ponto de destino. Esses testes point-in-polygon serão muito mais lentos que os testes de proximidade, que são a base das soluções oferecidas na sua pergunta anterior .
whuber
@ whuber: Eu tentei consultas baseadas em distância e o tempo em minutos. caminho para o alto. Pode ser que eu esteja errado em algum lugar. A partir desses pontos no polígono, leva tempo em segundos. Mesmo variando o buffer de 10 a 10000, o tempo é curto.
Shaunak
1
@ Shaunak Então há algo que importa com as consultas baseadas em distância, porque teoricamente elas podem ser feitas em média em microssegundos (ou melhor) e em milissegundos (pior caso) usando índices apropriados, como árvores KD . Você pode pensar em melhorá-los, em vez de procurar maneiras de otimizar a pesquisa point-in-buffer.
whuber
São dados da grade? Por que não usar uma varredura?
Matthew Snape

Respostas:

9

Tente executar o procedimento armazenado sp_help_spatial_geography_index para obter detalhes de como seu índice espacial está sendo usado. Você deve poder usar algo como:

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;

Poste os resultados em sua pergunta para ver se algo se destaca. O significado para cada um dos itens pode ser encontrado aqui .

Se suas coordenadas foram projetadas, você também pode fazer uma consulta não espacial simples nos campos X, Y calculados e verificar X <MinX e X> MaxX etc.

Projetar suas coordenadas (em um campo do tipo GEOMETRIA) também permite limitar seu índice espacial à extensão dos dados, o que pode acelerar consideravelmente o desempenho. Substitua as extensões mundiais pelas extensões de seus dados:

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
fonte
1
De acordo com technet.microsoft.com/en-us/library/bb934196.aspx o BOUNDING_BOX só pode ser usado para GEOMETRY_GRID, não GEOGRAPHY_GRID
Kelso
1
Resposta atualizada. O tipo GEOMETRY deve ser muito mais rápido, pois o BOUNDING_BOX pode ser definido.
geographika
1

Considere simplificar o buffer com BufferwithTolerance . Se os pontos estão bem compactados, o sistema precisa identificar se um ponto está em ambos os lados do limite. Quanto mais simples a linha, menos trabalho a máquina precisa fazer.

Matthew Snape
fonte