243 votes

Moyen le plus rapide pour trouver la Distance entre deux Points de Lat/Long

J’ai actuellement un peu moins 1 million sites dans une base de données mysql avec informations de latitude et de longitude.

J’ai essaye de trouver la distance entre un point et de nombreux autres points grâce à une requête. Il n’est pas aussi vite que je veux qu’il soit surtout avec 100 + visites par seconde.

Y a-t-il une requête plus rapide ou éventuellement un autre système plus rapide que mysql pour cela ? Je suis en utilisant cette requête :

121voto

Quassnoi Points 191041
  • Créez votre aide de points de Point valeurs Geometry types de données en MyISAM tableau

  • Créer un SPATIAL index sur ces points

  • Utiliser MBRContains() de trouver les valeurs:

    SELECT  *
    FROM    table
    WHERE   MBRContains(LineFromText(CONCAT(
            '('
            , @lon + 10 / ( 111.1 / cos(RADIANS(@lon)))
            , ' '
            , @lat + 10 / 111.1
            , ','
            , @lon - 10 / ( 111.1 / cos(RADIANS(@lat)))
            , ' '
            , @lat - 10 / 111.1 
            , ')' )
            ,mypoint)
    

ou, en MySQL 5.1 et au-dessus:

    SELECT  *
    FROM    table
    WHERE   MBRContains
                    (
                    LineString
                            (
                            Point
                                    (
                                    @lon + 10 / ( 111.1 / COS(RADIANS(@lat))),
                                    @lat + 10 / 111.1
                                    ) 
                            Point
                                    (
                                    @lon - 10 / ( 111.1 / COS(RADIANS(@lat))),
                                    @lat - 10 / 111.1
                                    ) 
                            ),
                    mypoint
                    )

Cela permet de sélectionner tous les points environ à l'intérieur de la zone de (@lat +/- 10 km, @lon +/- 10km).

En fait, ce n'est pas une zone, mais une forme sphérique rectangle: la latitude et la longitude lié segment de la sphère. Cela peut varier d'un simple rectangle sur le Franz Joseph Terrain, mais assez proche de la plupart des lieux habités.

  • Appliquer le filtrage supplémentaire pour sélectionner tous les éléments à l'intérieur du cercle (pas la place)

  • Pour appliquer l'amende supplémentaire de filtrage pour tenir compte de la grande distance du cercle (pour les grandes distances)

106voto

Binary Worrier Points 27424

Pas un MySql de réponse précise, mais ça va améliorer les performances de votre instruction sql.

Ce que vous êtes effectivement en train de faire est de calculer la distance de chaque point du tableau, pour voir si elle est dans les 10 unités d'un point donné.

Ce que vous pouvez faire avant de l'exécuter sql, c'est de créer quatre points de dessiner une boîte de 20 unités sur un côté, avec votre point dans le centre-je.e.. (x1,y1 ) . . . (x4, y4), où (x1,y1) est (givenlong + de 10 unités, givenLat + 10units) . . . (givenLong - 10units, givenLat -10 unités). En fait, vous avez seulement besoin de deux points, en haut à gauche et en bas à droite de les appeler (X1, Y1) et (X2, Y2)

Maintenant, votre instruction SQL utiliser ces points pour exclure les lignes qui sont certainement plus de 10u à partir de votre point donné, il peut utiliser des index sur les latitudes et les longitudes, de sorte que sera ordres de grandeur plus rapide que ce que vous avez actuellement.

par exemple

select . . . 
where locations.lat between X1 and X2 
and   locations.Long between y1 and y2;

La boîte approche peut retourner faux positifs (vous pouvez prendre des points dans les coins de la boîte qui sont > 10u à partir de ce point), si vous avez encore besoin de calculer la distance de chaque point. Cependant, ce nouveau sera beaucoup plus rapide parce que vous avez considérablement limité le nombre de points de test pour les points à l'intérieur de la boîte.

J'appelle cette technique "de la Pensée à l'intérieur de la boîte" :)

EDIT: cela Peut-il être mis dans une instruction SQL?

Je n'ai aucune idée de ce que mySql ou Php est capable de faire, désolé. Je ne sais pas où est le meilleur endroit est de construire les quatre points, ou comment ils pourraient être transmis à une requête mySql en Php. Cependant, une fois que vous avez les quatre points, il n'y a rien qui vous empêche de combiner votre propre SQL confession avec la mienne.

select name, 
       ( 3959 * acos( cos( radians(42.290763) ) 
              * cos( radians( locations.lat ) ) 
              * cos( radians( locations.lng ) - radians(-71.35368) ) 
              + sin( radians(42.290763) ) 
              * sin( radians( locations.lat ) ) ) ) AS distance 
from locations 
where active = 1 
and locations.lat between X1 and X2 
and locations.Long between y1 and y2
having distance < 10 ORDER BY distance;

Je sais avec MS SQL, je peux créer une instruction SQL qui déclare quatre chars (X1, Y1, X2, Y2) et calcule avant le "principal" instruction select, comme je l'ai dit, je n'ai aucune idée si cela peut être fait avec MySql. Cependant, je serais toujours enclins à construire les quatre points de C# et de les passer en paramètres à la requête SQL.

Désolé je ne peux pas être plus d'aide, si quelqu'un peut répondre à l'MySQL & Php certaines parties de cette, n'hésitez pas à modifier cette réponse à faire.

15voto

eillarra Points 1126

Consultez cette présentation pour une bonne réponse. Fondamentalement, il montre les deux approches différentes, montrés dans les commentaires, avec une explication détaillée sur pourquoi/quand vous devez utiliser l’un ou l’autre, et pourquoi le calcul « dans la boîte » peut être très intéressant.

Recherche de Distance de GEO avec MySQL

14voto

Brad Parks Points 5513

sur ce blog, la suite de MySql, la fonction a été validée. Je n'ai pas testé beaucoup, mais de ce que j'ai recueillies auprès de la poste, si votre latitude et longitude champs sont indexés, ce peut très bien fonctionner pour vous:

DELIMITER $$

DROP FUNCTION IF EXISTS `get_distance_in_miles_between_geo_locations` $$
CREATE FUNCTION get_distance_in_miles_between_geo_locations(geo1_latitude decimal(10,6), geo1_longitude decimal(10,6), geo2_latitude decimal(10,6), geo2_longitude decimal(10,6)) 
returns decimal(10,3) DETERMINISTIC
BEGIN
  return ((ACOS(SIN(geo1_latitude * PI() / 180) * SIN(geo2_latitude * PI() / 180) + COS(geo1_latitude * PI() / 180) * COS(geo2_latitude * PI() / 180) * COS((geo1_longitude - geo2_longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515);
END $$

DELIMITER ;

Exemple d'utilisation: En supposant une table appelée Lieux avec les champs latitude et longitude:

sélectionnez get_distance_in_miles_between_geo_locations(-34.017330, 22.809500, latitude, longitude) distance_from_input de lieux;

tout accroché à partir de ce post

4voto

siong1987 Points 791

http://PostGIS.Refractions.net/

Vous devrez peut-être regarder dans cette base de données qui est optimisé pour le stockage de la géolocalisation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X