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?