对于以下情况(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
答案 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
对其进行测试。