Mysql - выбрать записи для широты / долготы, которые пользователи имеют в своих индивидуальных диапазонах расстояний - PullRequest
0 голосов
/ 17 июня 2019

Мне нужно знать наилучшую практику (наилучшую производительность) для запроса к базе данных для следующего сценария (Mysql):

http://sqlfiddle.com/#!9/72191ca/1

У меня есть «стартовыйitem "(точка" Ключ ", синяя точка, лат: 47.471630, lng: 8.297835) с позицией широта / долгота.В пользовательской таблице есть пользователи (A, B, C и т. Д.) С их положением широты и долготы и их индивидуальными диапазонами в км.

Мне нужно запросить таблицу пользователей, чтобы найти идентификаторы, которые имеютключ в пределах их предопределенных диапазонов / расстояния.

Запрос должен быть оптимизирован - примерно 40 000 пользователей должны быть сопоставлены с позицией «ключ» широта / долгота.

Это текущий запрос, который я использую.Производительность довольно хорошая, но есть ли другое решение для этого, которое может использовать индексы?

DROP TABLE IF EXISTS users;

CREATE TABLE `users` (
  `user_id` char(1) NOT NULL,
  `lat` decimal(8,5) NOT NULL DEFAULT '0.00000',
  `lng` decimal(8,5) DEFAULT '0.00000',
  `user_range_km` decimal(10,1) NOT NULL DEFAULT '1.0',
  PRIMARY KEY (`user_id`),
  KEY `lat` (`lat`,`lng`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `users` (`user_id`, `lat`, `lng`, `user_range_km`) VALUES
('A', '47.46911', '8.29560', '0.4'),
('B', '47.48169', '8.30264', '0.4'),
('C', '47.49261', '8.31598', '2.9');

SELECT h.*, ( 6371 * acos( cos( radians(47.471630) ) * cos(  radians( h.lat ) ) * cos( radians( h.lng ) - radians(8.297835) ) + sin( radians(47.471630) ) * sin( radians( h.lat ) ) ) ) AS distance 
FROM users h 
HAVING distance <= h.user_range_km;

+---------+----------+---------+---------------+------------------+
| user_id | lat      | lng     | user_range_km | distance         |
+---------+----------+---------+---------------+------------------+
| A       | 47.46911 | 8.29560 |           0.4 | 0.32671077638732 |
| C       | 47.49261 | 8.31598 |           2.9 |  2.7021411331883 |
+---------+----------+---------+---------------+------------------+

В моем примере A и C имеют ключ на определенном расстоянии, поэтому мне нужно получить Aи C из запроса.См. SQL Fiddle

1 Ответ

0 голосов
/ 18 июня 2019

Есть 5 способов выполнить эту задачу.Ваш код - один из них, самый медленный.Вот мое обсуждение их: http://mysql.rjweb.org/doc.php/find_nearest_in_mysql

Самый простой следующий шаг - использовать технику "ограничивающего прямоугольника".Он включает в себя добавление двух предложений к WHERE и двух INDEXes.

. Ваши «несколько пользователей» вокруг одного «ключа» просто меняют роли.Традиционный вопрос касается «нескольких предметов (предприятий, грузовиков и т. Д.)» Вокруг «пользователя».Постройте ограничивающий прямоугольник вокруг «ключа».

При использовании только 40K пользователей техника ограничивающего прямоугольника, вероятно, будет достаточно хорошей.

ОК, у вас есть добавленная складка.Тем не менее, BB должен дать вам хороший первый фильтр.В вашем примере используйте

MAX(user_range_km) -- which is 2.9

в качестве радиуса для BB.(Или вдвое меньше ширины «ограничивающего квадрата», как указано в комментарии.)

Затем вместо простого тестирования каждого «расстояния» по 2,9, проверьте его по user_range_km.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...