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

cálculos de distância em consultas mysql


Opção 1:Faça o cálculo no banco de dados alternando para um banco de dados que suporte GeoIP.

Opção 2:Faça o cálculo no banco de dados usando um procedimento armazenado como este:
CREATE FUNCTION calcDistance (latA double, lonA double, latB double, LonB double)
    RETURNS double DETERMINISTIC
BEGIN
    SET @RlatA = radians(latA);
    SET @RlonA = radians(lonA);
    SET @RlatB = radians(latB);
    SET @RlonB = radians(LonB);
    SET @deltaLat = @RlatA - @RlatB;
    SET @deltaLon = @RlonA - @RlonB;
    SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) +
    COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2);
    RETURN 2 * ASIN(SQRT(@d)) * 6371.01;
END//

Se você tiver um índice de latitude e longitude em seu banco de dados, poderá reduzir o número de cálculos que precisam ser calculados elaborando uma caixa delimitadora inicial em PHP ($minLat, $maxLat, $minLong e $maxLong) e limitando as linhas para um subconjunto de suas entradas com base nisso (WHERE latitude BETWEEN $minLat AND $maxLat AND longitude BETWEEN $minLong AND $maxLong). Então o MySQL só precisa executar o cálculo de distância para esse subconjunto de linhas.

Se você está simplesmente usando um procedimento armazenado para calcular a distância), o SQL ainda precisa examinar todos os registros em seu banco de dados e calcular a distância para cada registro em seu banco de dados antes de decidir se deve retornar essa linha ou descartá-la .

Como o cálculo é relativamente lento para executar, seria melhor se você pudesse reduzir o conjunto de linhas que precisam ser calculadas, eliminando as linhas que claramente ficarão fora da distância necessária, de modo que estamos executando apenas o cálculo caro para um número menor de linhas.

Se você considerar que o que está fazendo é basicamente desenhar um círculo em um mapa, centrado em seu ponto inicial, e com um raio de distância; então a fórmula simplesmente identifica quais linhas estão dentro desse círculo... mas ainda precisa verificar cada linha.

Usar uma caixa delimitadora é como desenhar um quadrado no mapa primeiro com as bordas esquerda, direita, superior e inferior na distância apropriada do nosso ponto central. Nosso círculo será então desenhado dentro dessa caixa, com os pontos mais ao norte, mais a leste, mais ao sul e mais a oeste do círculo tocando as bordas da caixa. Algumas linhas ficarão fora dessa caixa, então o SQL nem se incomoda em tentar calcular a distância dessas linhas. Ele calcula apenas a distância para as linhas que estão dentro da caixa delimitadora para ver se elas também estão dentro do círculo.

Dentro do seu PHP (acho que você está executando o PHP a partir do nome da variável $), podemos usar um cálculo muito simples que calcula a latitude e longitude mínima e máxima com base em nossa distância e, em seguida, defina esses valores na cláusula WHERE do seu SQL demonstração. Esta é efetivamente a nossa caixa, e qualquer coisa que esteja fora dela é descartada automaticamente sem a necessidade de calcular sua distância.

Há uma boa explicação sobre isso (com código PHP) no Movable Type site essa deve ser uma leitura essencial para quem planeja fazer qualquer trabalho de GeoPositioning em PHP.

EDITAR O valor 6371,01 no procedimento armazenado calcDistance é o multiplicador para fornecer um resultado retornado em quilômetros. Use multiplicadores alternativos apropriados se quiser resultar em milhas, milhas náuticas, metros, o que for