lat / lon两个表之间的距离计算
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lat / lon两个表之间的距离计算相关的知识,希望对你有一定的参考价值。
我有以下两个表
城市
ID年,LON
山
ID,纬度,经度
SELECT cities.id,
(SELECT id FROM mountains
WHERE SQRT(POW(69.1 * ( latitude - cities.lat ) , 2 ) +
POW( 69.1 * (cities.lon - longitude ) *
COS( latitude / 57.3 ) , 2 ) )<20 LIMIT 1) as mountain_id
FROM cities
(查询耗时0.5060秒。)
为了复杂性,我删除了查询的某些部分(例如,按顺序排列,在哪里)。但是它确实不会影响执行时间。
下面的EXPLAIN。
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY cities ALL NULL NULL NULL NULL 478379
2 DEPENDENT SUBQUERY mountains ALL NULL NULL NULL NULL 15645 Using where
使用SELECT本身不是我的问题,但是当我尝试使用给定的结果时......例如
id mountain_id
588437 NULL
588993 4269
589014 4201
589021 4213
589036 4952
589052 7625
589113 9235
589125 NULL
589176 1184
589210 4317
...更新表格一切都变得非常缓慢。我几乎尝试了所有我所知道的事情。我知道依赖子查询不是最佳的,但我不知道如何摆脱它。
有没有办法改善我的查询。也许把它变成一个JOIN?
除了纬度和经度之外,这两个表本身并没有什么共同点,它们是不同的,只是在使用计算时才会产生关系。
MariaDB中的空间距离搜索(km,miles)似乎尚不可用。
快速进行这种操作的技巧是避免在每对可能的lat / lon点上进行所有计算。为此,您应该合并一个边界框操作。
让我们从使用JOIN开始。在伪代码中,你想要这样的东西,但是如果你抓住一些额外的对子并不重要,只要它们比其他对更远。
SELECT c.city_id, m.mountain_id
FROM cities c
JOIN mountains m ON distance_in_miles(c, m) < 20
因此,我们需要弄清楚如何快速制作ON子句 - 让它使用索引而不是在所有城市和山区漫步(向Woody Guthrie道歉)。
让我们试试这个ON子句。它在+/- 20英里的方形边界框内搜索附近的对。
SELECT c.city_id, m.mountain_id
FROM cities c
JOIN mountains m
ON m.lat BETWEEN c.lat - (20.0 / 69.0)
AND c.lat + (20.0 / 69.0)
AND m.lon BETWEEN c.lon - (20.0 / (69.0 * COS(RADIANS(c.lat))))
AND c.lon + (20.0 / (69.0 * COS(RADIANS(c.lat))))
在此查询中,20.0
是比较极限半径,69.0
是每纬度纬度定义法定英里的常量。
然后,在两个表上的(lat, lon, id)
上放置复合索引,并且您的JOIN
操作将能够使用索引范围扫描来提高查询效率。
最后,您可以使用伪代码以这些类型的子句扩充该查询
ORDER BY dist_in_miles (c,m) ASC
LIMIT 1
在这里,您实际上需要使用距离公式。你问题中的笛卡尔距离公式是一个近似值,除非你靠近极点,否则它可以很好地运行。您可能希望使用大圆公式。这些被称为球形余弦定律,半正弦或Vincenty公式。
以上是关于lat / lon两个表之间的距离计算的主要内容,如果未能解决你的问题,请参考以下文章