Esta é a minha primeira pergunta aqui, então tenha paciência comigo!
Estou implementando um back-end para um aplicativo móvel que terá que fazer pesquisas de proximidade para encontrar POIs próximos (pontos de interesse). Sei que é um cenário muito comum e parece muito simples, mas há muitas maneiras diferentes de implementá-lo. Por isso, gostaria de ver como profissionais mais experientes estão implementando essas pesquisas espaciais simples.
Como um POI é apenas um PONTO, não precisamos de cálculos complexos envolvendo cruzamentos ou similares. Por isso, pensei inicialmente que o uso de colunas e índices espaciais GEOGRAPHY poderia ser um exagero ou até mais lento do que outras estratégias. Então, reduzi-o a três abordagens:
1) Coluna GEOGRAFIA + Índice Espacial
Essa talvez seja a solução de fato para esse problema. Como temos índices espaciais e colunas geográficas, podemos apenas usá-lo e pesquisar por distância. Algo assim.
SELECT * FROM POIs WHERE Loc.STDistance(@radius) <= @distance;
Como temos um índice espacial no Loc, deve ser muito rápido.
2) Usando uma "caixa delimitadora" sobre as colunas Latitude e Longitude
Essa é a abordagem trivial sem envolver índices espaciais. Encontramos uma caixa delimitadora para nosso ponto e raio e, em seguida, basta pesquisar nas colunas Latitude e Longitude. Se ambos estiverem indexados, essa pesquisa deverá ser muito rápida. Teremos que aplicar a função de distância para filtrar alguns valores fora do "círculo", mas dentro da caixa delimitadora. Mas isso deve ser bem rápido. Esta ideia é melhor explicada aqui: http://www.movable-type.co.uk/scripts/latlong-db.html
Algo assim:
DECLARE @lat float
DECLARE @lon float
SET @lat = -23.001029
SET @lon = -43.328422
DECLARE @maxLat float, @minLat float, @maxlon float, @minLon float
DECLARE @R float
DECLARE @distance FLOAT = 100 -- A distance in meters
SET @R = 6378137 -- Earth
SET @maxLat = @lat + DEGREES(@distance/@R)
SET @minLat = @lat - DEGREES(@distance/@R)
SET @maxLon = @lon + DEGREES((@distance/@R/COS(RADIANS(@lat))))
SET @minLon = @lon - DEGREES((@distance/@R/COS(RADIANS(@lat))))
SELECT * from POIs
WHERE
Lat Between @minLat And @maxLat
And Lng Between @minLon And @maxLon
3) Use um GEOHASH integral armazenado em uma coluna indexada
Essa abordagem é muito interessante e é algo que as pessoas estão usando em conjunto com os conjuntos solicitados pelo REDIS para fazer pesquisas de proximidade. O princípio pode ser transposto para o SQL Server usando uma coluna indexada que armazena o GEOHASH integral.
Eu tenho essa ideia de Ardb: https://github.com/yinqiwen/ardb/wiki/Spatial-Index
Também é explicado de uma maneira um pouco mais amigável aqui: Usando o geohash para pesquisas por proximidade?
Em outras palavras, calcularíamos um GEOHASH com uma profundidade de bits correspondente ao raio da pesquisa que desejássemos, depois calcularíamos 8 geohashes nos arredores e finalmente enviaríamos uma pesquisa usando essas geohashs como caixas delimitadoras na coluna indexada. Serão 9 ENTRE operadores na cláusula WHERE do SQL ... Os resultados terão que ser filtrados devido ao retorno de um POI falso.
Mas parece que isso será mais lento que o método 2, pois a cláusula where será mais complexa, embora apenas faça uma consulta sobre uma única coluna em vez de duas.
Alguém tem alguma experiência para compartilhar sobre isso? Existe uma abordagem melhor / correta para isso?
fonte
Respostas:
O motivo pelo qual os bancos de dados implementam índices R-tree para espacial é porque eles são mais rápidos que geohashes ou pesquisas em índices x e y separados. O problema das geohashes é que você precisa pesquisar 9 quadrantes, e não apenas 1, para fazer pesquisas por tipo de proximidade - consulte as limitações de geohash . Eles são úteis em bancos de dados que não possuem árvores R, para permitir a expressão de um objeto com um intervalo 2D, em uma dimensão, que pode ser indexada com uma árvore B. Ter índices separados (ou compostos) em xey também será mais lento, pois você precisa digitalizar mais do índice para zerar sua área de interesse, enquanto que com as árvores R, a pesquisa de índice está na caixa delimitadora.
O uso varia, mas não é um exagero usar o espaço apenas porque você só tem pontos. Você não perde nada usando um tipo de geometria e potencialmente ganha muito (não apenas em termos de velocidade), mas em provas futuras. E se você quiser adicionar buffer ou interseção de polígono posteriormente? Por fim, a única maneira de saber é testar seu caso de uso, mas meu 2c é a abordagem de uso 1.
fonte