Самый быстрый способ найти расстояние между двумя точками Lat/Long

Я последовал совету Дэвида Гласса, хотя казалось, что у меня есть проблема. Я обновил свой файл package.json, чтобы devDependencies совпал с зависимостями, и затем предупреждение исчезло.

215
задан kaiser 29 March 2017 в 09:02
поделиться

3 ответа

  • Create your points using Point values of Geometry data types in MyISAM table. As of Mysql 5.7.5, InnoDB tables now also support SPATIAL indices.

  • Create a SPATIAL index on these points

  • Use MBRContains() to find the values:

    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)
    

, or, in MySQL 5.1 and above:

    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
                    )

This will select all points approximately within the box (@lat +/- 10 km, @lon +/- 10km).

This actually is not a box, but a spherical rectangle: latitude and longitude bound segment of the sphere. This may differ from a plain rectangle on the Franz Joseph Land, but quite close to it on most inhabited places.

  • Apply additional filtering to select everything inside the circle (not the square)

  • Possibly apply additional fine filtering to account for the big circle distance (for large distances)

112
ответ дан 23 November 2019 в 04:21
поделиться

Not a MySql specific answer, but it'll improve the performance of your sql statement.

What you're effectively doing is calculating the distance to every point in the table, to see if it's within 10 units of a given point.

What you can do before you run this sql, is create four points that draw a box 20 units on a side, with your point in the center i.e.. (x1,y1 ) . . . (x4, y4), where (x1,y1) is (givenlong + 10 units, givenLat + 10units) . . . (givenLong - 10units, givenLat -10 units). На самом деле вам нужны только две точки, верхняя левая и нижняя правая назовите их (X1, Y1) и (X2, Y2).

Теперь ваш оператор SQL использует эти точки, чтобы исключить строки, которые определенно больше 10u от вашего для данной точки он может использовать индексы по широте и долготе, поэтому будет на несколько порядков быстрее, чем у вас в настоящее время.

например

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

Коробочный подход может возвращать ложные срабатывания (вы можете выбрать точки в углах прямоугольник на расстоянии> 10u от заданной точки), поэтому вам все равно нужно рассчитать расстояние до каждой точки. Однако это снова будет намного быстрее, потому что вы резко ограничили количество точек для тестирования до точек внутри рамки.

Я называю эту технику «Мыслить внутри коробки» :)

РЕДАКТИРОВАТЬ: I don't know where the best place is to build the four points, or how they could be passed to a mySql query in Php. However, once you have the four points, there's nothing stopping you combining your own SQL statement with mine.

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;

I know with MS SQL I can build a SQL statement that declares four floats (X1, Y1, X2, Y2) and calculates them before the "main" select statement, like I said, I've no idea if this can be done with MySql. However I'd still be inclined to build the four points in C# and pass them as parameters to the SQL query.

Sorry I can't be more help, if anyone can answer the MySQL & Php specific portions of this, feel free to edit this answer to do so.

97
ответ дан 23 November 2019 в 04:21
поделиться

Проверьте эту презентацию, чтобы получить хороший ответ. В основном она показывает два разных подхода, показанных в комментариях, с подробным объяснением почему / когда следует использовать тот или иной вариант и почему расчет «в коробке» может быть очень интересным.

Географический поиск расстояния с MySQL

15
ответ дан 23 November 2019 в 04:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: