Mysql
 sql >> Base de données >  >> RDS >> Mysql

calculs de distance dans les requêtes mysql

Option 1 :Effectuez le calcul sur la base de données en basculant vers une base de données prenant en charge GeoIP.

Option 2 :Effectuez le calcul sur la base de données à l'aide d'une procédure stockée comme celle-ci :

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 vous avez un index sur la latitude et la longitude dans votre base de données, vous pouvez réduire le nombre de calculs qui doivent être calculés en travaillant une boîte de délimitation initiale en PHP ($minLat, $maxLat, $minLong et $maxLong), et en limitant les lignes à un sous-ensemble de vos entrées en fonction de cela (WHERE latitude BETWEEN $minLat AND $maxLat AND longitude BETWEEN $minLong AND $maxLong). Ensuite, MySQL n'a plus qu'à exécuter le calcul de distance pour ce sous-ensemble de lignes.

Si vous utilisez simplement une procédure stockée pour calculer la distance), SQL doit toujours parcourir chaque enregistrement de votre base de données et calculer la distance pour chaque enregistrement de votre base de données avant de pouvoir décider de renvoyer cette ligne ou de la supprimer. .

Étant donné que le calcul est relativement lent à exécuter, il serait préférable de réduire l'ensemble de lignes à calculer, en éliminant les lignes qui tomberont clairement en dehors de la distance requise, de sorte que nous n'exécutons que le calcul coûteux pour un plus petit nombre de lignes.

Si vous considérez que ce que vous faites consiste essentiellement à dessiner un cercle sur une carte, centré sur votre point initial et avec un rayon de distance ; ensuite, la formule identifie simplement les lignes qui se trouvent dans ce cercle... mais elle doit toujours vérifier chaque ligne.

Utiliser une boîte englobante revient à dessiner d'abord un carré sur la carte avec les bords gauche, droit, supérieur et inférieur à la distance appropriée de notre point central. Notre cercle sera alors dessiné à l'intérieur de cette boîte, avec les points les plus au nord, les plus à l'est, les plus au sud et les plus à l'ouest sur le cercle touchant les bords de la boîte. Certaines lignes tomberont en dehors de cette boîte, donc SQL ne prend même pas la peine d'essayer de calculer la distance pour ces lignes. Il calcule uniquement la distance pour les lignes qui se trouvent dans la zone de délimitation pour voir si elles se trouvent également dans le cercle.

Dans votre PHP (imaginez que vous exécutez PHP à partir du nom de la variable $), nous pouvons utiliser un calcul très simple qui calcule la latitude et la longitude minimales et maximales en fonction de notre distance, puis définissez ces valeurs dans la clause WHERE de votre SQL déclaration. C'est effectivement notre boîte, et tout ce qui tombe en dehors de celle-ci est automatiquement rejeté sans qu'il soit nécessaire de calculer sa distance.

Il y a une bonne explication de cela (avec du code PHP) sur le Movable Type site Web cela devrait être une lecture essentielle pour quiconque envisage de faire des travaux de géopositionnement en PHP.

MODIFIER La valeur 6371,01 dans la procédure stockée calcDistance est le multiplicateur pour vous donner un résultat renvoyé en kilomètres. Utilisez des multiplicateurs alternatifs appropriés si vous souhaitez obtenir des résultats en miles, miles nautiques, mètres, etc.