Поиск ближайших мест, используя тип данных точки и st_distance_sphere в MySQL 8 - PullRequest
0 голосов
/ 20 мая 2018

У меня есть таблица с именем place:

id | name       | coordinates (longitude, latitude)
1  | London     | -0.12574, 51.50853
2  | Manchester | -2.25, 53.41667
3  | Glasgow    | -4.25, 55.86667

Столбец coordinates имеет тип данных point .Я вставил точки в таблицу place, используя:

st_geomfromtext('point($longitude $latitude)', 4326)

Обратите внимание, что я использовал SRID.

Учитывая любые координаты, я хотел бы найти ближайшийместа к нему (порядок по возрастанию).Решение, которое я в настоящее время придумываю (читая документы по MySQL), выглядит следующим образом:

select
    *,
    st_distance_sphere(`place`.`coordinates`, st_geomfromtext('Point($longitude $latitude)', 4326)) as distance
from place
order by distance asc;

После рассмотрения бесчисленных подобных вопросов здесь и в других местах, совершенно очевидно, что это менее известно (иновый способ), поэтому в этом нет особого смысла, поэтому я ищу немного разъяснений.

Мои вопросы:

  1. Это лучшее решение?/ Я правильно это делаю?
  2. Будет ли этот метод использовать пространственный индекс, который у меня есть в столбце coordinates?
  3. При использовании st_distance_sphere , нужно ли мнеуказать радиус Земли, чтобы получить точные результаты?(Правка: нет, по умолчанию используется радиус Земли)

Правка, вот такие ответы:

explain select ...; возвращает:

id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra
1  | SIMPLE      | place | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 115687 | 100.00   | Using filesort

flush status; select ...; show session status like 'Handler%'; возвращает:

Variable_name              | Value
Handler_commit             | 1
Handler_delete             | 0
Handler_discover           | 0
Handler_external_lock      | 2
Handler_mrr_init           | 0
Handler_prepare            | 0
Handler_read_first         | 1
Handler_read_key           | 1001
Handler_read_last          | 0
Handler_read_next          | 0
Handler_read_prev          | 0
Handler_read_rnd           | 1000
Handler_read_rnd_next      | 119395
Handler_rollback           | 0
Handler_savepoint          | 0
Handler_savepoint_rollback | 0
Handler_update             | 0
Handler_write              | 0

1 Ответ

0 голосов
/ 24 мая 2018

Это может быть лучшим решением.Давайте сначала получим несколько других ответов ...

Что говорит EXPLAIN SELECT ...?(Это может ответить на ваш Q2).

Ваш запрос отсканирует всю таблицу, независимо от других ответов.Возможно, вы хотите LIMIT ... в конце?

Еще одна вещь, которая может быть полезна (в зависимости от вашего приложения и оптимизатора): добавьте ограничивающую рамку к предложению WHERE.

В любом случае, чтобы получить точное представление о количестве фактически затронутых строк, выполните следующие действия:

FLUSH STATUS;
SELECT ...;
SHOW SESSION STATUS LIKE 'Handler%';

Вернитесь с этими ответами;тогда, возможно, мы можем продолжить итерацию.

После SHOW STATUS

Ну, Handler_read_rnd_next говорит, что это было полное сканирование таблицы.1000 и 1001 - у вас было LIMIT 1000?

Я делаю вывод, что LIMIT не учитывает принцип работы SPATIAL.То есть он делает упрощенную вещь - (1) проверяет все строки, (2) сортирует, (3) LIMIT.

Итак, что делать?

План A:Решите, что вы не хотите получать результаты дальше, чем X миль (км), и добавьте «ограничивающий прямоугольник» к запросу.

План B: Откажитесь от Spatial и найдите более сложный способ выполнения задачи: http://mysql.rjweb.org/doc.php/latlng

...