Mysql lat/lon两个表之间的距离计算
我有下面两张桌子 城市 id,lat,lon 山 id、纬度、经度Mysql lat/lon两个表之间的距离计算,mysql,performance,select,subquery,mariadb,Mysql,Performance,Select,Subquery,Mariadb,我有下面两张桌子 城市 id,lat,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 mounta
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
使用SELECT本身不是我的问题,但是当我尝试使用给定的结果时。。。e、 g
id mountain_id
588437 NULL
588993 4269
589014 4201
589021 4213
589036 4952
589052 7625
589113 9235
589125 NULL
589176 1184
589210 4317
…要更新表,一切都变得非常缓慢。我几乎尝试了我所知道的一切。我知道依赖子查询不是最优的,但我不知道如何摆脱它
有没有办法改进我的查询。也许把它改成一个连接
这两个表本身除了纬度和经度之外没有任何共同之处,纬度和经度是不同的,只有在使用计算时才相互关联
MariaDB中的空间距离搜索(km,miles)似乎还不可用。快速执行此类操作的诀窍是避免对每一对可能的lat/lon点进行所有计算。为此,应合并边界框操作 让我们从使用连接开始。在伪代码中,您需要这样的东西,但如果捕获了一些额外的对,则无所谓,只要它们比其他对相距更远
SELECT c.city_id, m.mountain_id
FROM cities c
JOIN mountains m ON distance_in_miles(c, m) < 20
在此查询中,20.0
是比较极限半径,69.0
是定义每纬度法定英里数的常数
然后,在两个表的(lat、lon、id)
上放置复合索引,您的JOIN
操作将能够使用索引范围扫描来提高查询效率
最后,您可以在伪代码中使用这些类型的子句来扩充该查询
ORDER BY dist_in_miles (c,m) ASC
LIMIT 1
这里实际上需要使用一个距离公式。你问题中的笛卡尔距离公式是一个近似值,除非你在极点附近,否则效果相当好。您可能需要使用大圆公式来代替。这些被称为球面余弦定律、哈弗森公式或文森特公式。看起来你想要的是彼此相距20法定英里以内的所有成对(城市/山脉)。对吗?它现在就是这么做的。20英里只是为了减少结果的数量。当我按距离添加顺序时(为了复杂起见,我现在省略了这个顺序),它给出了表1到表2之间最接近的匹配。提前感谢!我试过你的方法。现在看起来慢多了,但我还没有添加所有的过滤器。如何筛选结果以获得每个城市id的一个结果?限制会影响整个结果集。最后,我希望看到一个列表,就像我在原来的帖子中看到的那样,我得到一个城市id和一个山区id。
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))))
ORDER BY dist_in_miles (c,m) ASC
LIMIT 1