Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Índice Espacial não sendo usado


Infelizmente ST_Distance() < threshold não é um sargable critério de busca. Para satisfazer essa consulta, o MySQL deve calcular o valor da função para cada linha na tabela e, em seguida, compará-lo com o limite. Portanto, ele precisa fazer uma varredura completa da tabela (ou talvez uma varredura completa do índice).

Para explorar um índice para acelerar essa consulta, você precisará de um critério de caixa delimitadora. A consulta é muito mais elaborada, mas também muito mais rápida. Supondo que seus pontos x/y em sua geometria representem latitude/longitude em graus, essa consulta pode ficar assim:
   set @latpoint = 38.0234332;
   set @lngpoint = -94.0724223;
   set @r = 10.0;    /* ten mile radius */
   set @units=69.0;    /* 69 statute miles per degree */
   SELECT AsText(geo) 
     FROM markers
      WHERE MbrContains(GeomFromText( 
       CONCAT('LINESTRING(', @latpoint-(@r/@units),' ',
                             @lngpoint-(@r /(@units* COS(RADIANS(@latpoint)))), 
                          ',', 
                             @latpoint+(@r/@units) ,' ', 
                             @lngpoint+(@r /(@units * COS(RADIANS(@latpoint)))),
                           ')')),
                    geo) 

Como é que isso funciona? Por um lado, o MbrContains( vinculado, item) função é sargable . Por outro lado, o item concat grande e feio produz uma linha diagonal do sudoeste ao canto nordeste do retângulo delimitador. Usando seu ponto de dados e raio de dez milhas, fica assim.
LINESTRING(37.8785 -94.2564,38.1684 -93.8884)

Quando você usa o GeomFromText() renderização dessa linha diagonal no primeiro argumento para MbrContains() ele serve como um retângulo delimitador. MbrContains() pode então explorar o índice de geometria quadtree bacana.

Em terceiro lugar, ST_Distance() , no MySQL, não lida com cálculos de latitude e longitude de grandes círculos. (PostgreSQL tem uma extensão GIS mais abrangente .) MySQL é tão burro quanto um flapjack em flatland. Ele assume que seus pontos em seus objetos geométricos são representados em geometria plana. Então ST_Distance() < 10.0 com pontos lng/lat faz algo estranho.

Há uma falha nos resultados que esta consulta gera; ele retorna todos os pontos na caixa delimitadora, não apenas dentro do raio especificado. Isso pode ser resolvido com um cálculo de distância separado. Eu escrevi tudo isso com alguns detalhes aqui .

Observação :Para latitude e longitude com resolução de GPS, FLOAT de 32 bits dados têm precisão suficiente. DOUBLE é o que a extensão geográfica do MySQL usa. Quando você está trabalhando em graus, mais de cinco casas após o ponto decimal está além da precisão do GPS. DECIMAL() não é um tipo de dados ideal para coordenadas de latitude/longitude.