我正在制作一个具有地理位置的应用程序,所以我有一个城市表,其中有超过200万条记录,并且我想获取最接近记录的已定义纬度和经度,并在两列上都有索引。该代码实现了我想要的功能,但是要花3到4秒钟才能实现。
我试图将索引放在经度和纬度上,并且仅在经度上。我还尝试将纬度和经度分别设置为索引。
SELECT * FROM Cities
ORDER BY ABS(someLatitude - latitude) ASC, ABS(someLongitude - longitude) ASC
LIMIT 1
我希望代码在不到一秒钟的时间内执行。我该怎么办?
答案 0 :(得分:0)
ORDER BY ABS(someLatitude - latitude) ASC,
ABS(someLongitude - longitude) ASC
WTF?这样一来,所有纬度非常相似的城市都将汇集在一起-甚至包括来自地球另一端的那些城市!
mysql> SELECT country, city, lat, lng FROM `cities`
WHERE population > 0
ORDER BY ABS(lat - 36) ASC,
ABS(lng - 0) ASC LIMIT 10;
+---------+-----------+---------+----------+
| country | city | lat | lng |
+---------+-----------+---------+----------+
| jp | Okegawa | 36 | 139.557 |
| us | Sapulpa | 35.9986 | -96.1139 |
| us | Avenal | 36.0042 | -120.128 |
| cn | Zhucheng | 35.9947 | 119.397 |
| us | Durham | 35.9939 | -78.8989 |
| us | Espanola | 35.9911 | -106.08 |
| jp | Chichibu | 35.9903 | 139.076 |
| us | Oak Ridge | 36.0103 | -84.2697 |
| ir | Baneh | 35.9894 | 45.8953 |
| es | Tarifa | 36.0125 | -5.60556 |
+---------+-----------+---------+----------+
10 rows in set (0.90 sec)
请注意,日本,美国,中国,爱尔兰和西班牙的城市基于该ORDER BY
彼此“接近”。 (我的列表中有3百万个城市,其中许多人口= 0。)
第一个优化是选择一个最大距离,并在中心周围绘制一个“边界框”。并有一个索引:
mysql> SELECT country, city, lat, lng FROM `cities` WHERE population > 0
-> AND lat BETWEEN 36-2 AND 36+2
-> AND lng BETWEEN -84-3 AND -84+3
-> LIMIT 10;
+---------+---------------+---------+----------+
| country | city | lat | lng |
+---------+---------------+---------+----------+
| us | Gadsden | 34.0142 | -86.0067 |
| us | Cedartown | 34.0536 | -85.255 |
| us | Acworth | 34.0658 | -84.6769 |
| us | Kennesaw | 34.0233 | -84.6156 |
| us | Woodstock | 34.1014 | -84.5194 |
| us | Mountain Park | 34.0808 | -84.4114 |
| us | Roswell | 34.0231 | -84.3617 |
| us | Alpharetta | 34.0753 | -84.2942 |
| us | Duluth | 34.0028 | -84.1447 |
| us | Suwanee | 34.0514 | -84.0714 |
+---------+---------------+---------+----------+
使用INDEX(lat)
或INDEX(lng)
或INDEX(lat,lng)
或INDEX(lng,lat)
。 (这些索引的优劣程度大致相同。但是仍然必须查看25.7万行,即4度(276英里或444公里宽)条带中的所有行。
如果不限制距离,索引将无用,因为它会查看所有行。
它需要某种ORDER BY
子句来计算距离(毕达哥拉斯或Great-Circle)才能获得“最近”。
要真正提高效率,需要付出更多的努力:http://mysql.rjweb.org/doc.php/latlng 那在一定程度上讨论了这个问题为什么很棘手。