MySQL-选择用户在各自距离范围内的经/纬度位置记录

时间:2019-06-17 07:07:33

标签: mysql latitude-longitude

对于以下情况(Mysql),我需要了解数据库查询的最佳实践(最佳性能):

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

我有一个带有纬度/经纬度的“起始项”(点“键”,蓝点lat:47.471630,lng:8.297835)。在用户表中,有一些用户(A,B,C等),其纬度/经度位置以及各自的距离以km为单位。

我需要查询用户表以查找具有在其预定义范围/距离内的键的ID。

查询应进行优化-将大约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 :(得分:0)

有5种方法可以完成该任务。您的代码是其中之一,是最慢的代码。这是我对它们的讨论:http://mysql.rjweb.org/doc.php/find_nearest_in_mysql

最简单的下一步是使用“边界框”技术。它涉及在WHERE和两个INDEXes上添加2个子句。

您围绕一个“键”的“多个用户”只是颠倒了角色。传统的问题是关于“用户”周围的“多个项目(企业,卡车等)”。围绕“键”构建边界框。

只有4万名用户,边界框技术可能足够好。

好的,您的皱纹增加了。尽管如此,BB应该给您一个很好的第一个过滤器。在您的示例中,使用

MAX(user_range_km) -- which is 2.9

作为BB的半径。 (或在注释中提到的“边界正方形”宽度的一半。)

然后,而不是简单地针对2.9测试每个“距离”,而是针对user_range_km对其进行测试。