【发布时间】:2019-06-18 12:23:27
【问题描述】:
我需要了解以下场景 (Mysql) 的数据库查询的最佳实践(最佳性能):
http://sqlfiddle.com/#!9/72191ca/1
我有一个带有纬度/经度位置的“起始项目”(点“关键”,蓝点 lat:47.471630, lng: 8.297835 )。在用户表中,有用户(A、B、C 等)及其纬度/经度位置和以公里为单位的个人范围。
我需要查询 users 表以查找在其预定义范围/距离内具有键的 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 的 Key 在其定义的距离内,因此我需要将 A 和 C 排除在查询之外。请参阅 SQL 小提琴
【问题讨论】:
-
添加了sqlfiddle
-
这是一个经常被问到的问题 - 无论是在这里还是在其他地方 - 因为很多人希望快速有效地对大量(而不是如此庞大)的地理数据点集合进行排序。一个技巧是排除不适合边界正方形的数据,边数等于“距离”的两倍。
-
好吧,我知道如何在查询中使用边界框,我们有一个起点,其中有一个范围来查询用户纬度/经度以排除框外的用户。但是我在这里看不到这种情况,因为每个用户都有一个“个人”边界框。或者您的意思是,在查询中将使用边界框 lat/lngs 而不是直接使用它们的 lat/lngs?还是我在这里漏掉了一点?
-
正如我所说,这是一个被广泛讨论的话题。