sql >> Base de Datos >  >> RDS >> Mysql

cálculos de distancia en consultas mysql

Opción 1:Realice el cálculo en la base de datos cambiando a una base de datos que admita GeoIP.

Opción 2:Haz el cálculo en la base de datos usando un procedimiento almacenado 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//

Si tiene un índice de latitud y longitud en su base de datos, puede reducir la cantidad de cálculos que deben calcularse elaborando un cuadro delimitador inicial en PHP ($minLat, $maxLat, $minLong y $maxLong) y limitando las filas a un subconjunto de sus entradas basadas en eso (DONDE la latitud ENTRE $minLat Y $maxLat Y longitud ENTRE $minLong Y $maxLong). Entonces MySQL solo necesita ejecutar el cálculo de distancia para ese subconjunto de filas.

Si simplemente está utilizando un procedimiento almacenado para calcular la distancia), entonces SQL todavía tiene que revisar cada registro en su base de datos y calcular la distancia para cada registro en su base de datos antes de que pueda decidir si devolver esa fila o descartarla. .

Debido a que el cálculo es relativamente lento de ejecutar, sería mejor si pudiera reducir el conjunto de filas que deben calcularse, eliminando las filas que claramente quedarán fuera de la distancia requerida, de modo que solo estemos ejecutando el cálculo costoso para un número menor de filas.

Si consideras que lo que estás haciendo es básicamente dibujar un círculo en un mapa, centrado en tu punto inicial, y con un radio de distancia; luego, la fórmula simplemente identifica qué filas se encuentran dentro de ese círculo... pero todavía tiene que verificar cada fila.

Usar un cuadro delimitador es como dibujar un cuadrado en el mapa primero con los bordes izquierdo, derecho, superior e inferior a la distancia adecuada de nuestro punto central. Nuestro círculo se dibujará dentro de ese cuadro, con los puntos más al norte, más al este, más al sur y más al oeste del círculo tocando los bordes del cuadro. Algunas filas quedarán fuera de ese cuadro, por lo que SQL ni siquiera se molesta en intentar calcular la distancia para esas filas. Solo calcula la distancia de aquellas filas que caen dentro del cuadro delimitador para ver si también caen dentro del círculo.

Dentro de su PHP (supongo que está ejecutando PHP desde el nombre de la variable $), podemos usar un cálculo muy simple que calcula la latitud y longitud mínima y máxima en función de nuestra distancia, luego establezca esos valores en la cláusula WHERE de su SQL declaración. Esta es efectivamente nuestra caja, y todo lo que cae fuera de ella se descarta automáticamente sin necesidad de calcular realmente su distancia.

Hay una buena explicación de esto (con código PHP) en el Movable Type sitio web esa debería ser una lectura esencial para cualquiera que planee hacer cualquier trabajo de geoposicionamiento en PHP.

EDITAR El valor 6371.01 en el procedimiento almacenado calcDistance es el multiplicador para brindarle un resultado devuelto en kilómetros. Utilice multiplicadores alternativos apropiados si desea generar millas, millas náuticas, metros, lo que sea