使用纬度/经度索引mysql表以进行地理查找
我有一个遗留innodb表,其中包含一个具有纬度/经度的业务。给定一个输入纬度/经度(低于51.2167/4.41667),查询将按距离(公里)的顺序返回第一个激活、启用、未删除的30个业务。与accounts表的联接用于检查列表的有效性使用纬度/经度索引mysql表以进行地理查找,mysql,database,geospatial,latitude-longitude,indexing,Mysql,Database,Geospatial,Latitude Longitude,Indexing,我有一个遗留innodb表,其中包含一个具有纬度/经度的业务。给定一个输入纬度/经度(低于51.2167/4.41667),查询将按距离(公里)的顺序返回第一个激活、启用、未删除的30个业务。与accounts表的联接用于检查列表的有效性 select listing.* from listing listing , account account where listing.account_id = account.id and listing.a
select
listing.*
from
listing listing ,
account account
where
listing.account_id = account.id
and listing.active = 1
and listing.approved = 1
and listing.deleted = 0
and listing.enabled = 1
and account.enabled = 1
and account.activated_by_user = 1
group by
listing.id
having
111.222569*degrees(acos(sin(radians(listing.latitude))*sin(radians( 51.2167)) +cos(radians(listing.latitude))*cos(radians( 51.2167))*cos(radians(listing.longitude - 4.41667)))) < 250
order by
111.222569*degrees(acos(sin(radians(listing.latitude))*sin(radians( 51.2167)) +cos(radians(listing.latitude))*cos(radians( 51.2167))*cos(radians(listing.longitude - 4.41667))))
limit 30;
非常感谢您的帮助。您可能想看看。不幸的是,您无法在任何非
几何体
类型的列上创建空间
索引,因此,您至少需要向表中添加一列。这需要很长时间,因为您的查询正在为50k行表中的每一行计算一次带有所有超越函数的大圆距离公式(包括排序时两次)
你能限制你搜索的距离吗?您可能已经注意到,大多数store finder web应用程序都有一个下拉菜单项,可以选择“5英里以内”、“10英里以内”等等
如果你能做到这一点,你应该在你的搜索中添加一个WHERE子句,并通过在你的纬度列上放置一个索引来优化它。假设您使用值RANGELIMIT作为搜索范围限制,以英里为单位
试试这个条款
WHERE LISTING.LATITUDE BETWEEN LOCATION.LATITUDE - (RANGELIMIT * 1.1508/60)
AND LOCATION.LATITUDE + (RANGELIMIT * 1.1508/60)
这是因为一海里几乎完全等于一分钟(1/60)的纬度。1.1508系数将海里转换为法定英里
我建议的子句将使用纬度索引来缩小搜索范围,并且计算大圆距离的频率将大大降低
您还可以包含一个关于经度的BETWEEN子句。但根据我的经验,只需在搜索之间选择一个纬度,就能得到非常好的结果。你好,奥利,谢谢你的明确解释。然而,到目前为止,我没有太多的运气通过你的建议缩小搜索范围来显著加快查询速度,即使使用纬度索引。我将进行更多的实验。提高速度的是更改select:select id、纬度、经度而不是select listing。*并随后对listing表执行查询以获取其余数据。我想知道是否值得创建一个单独的MyISAM表来存储列表id和几何体以用于搜索。有人对这些空间索引的速度有经验吗?我不确定是否有可能建立一个能够计算出二维距离的索引。索引的目的是以有序的方式预加载搜索的某些方面。条件之间的经度计算方法是否与纬度计算方法相同?
WHERE LISTING.LATITUDE BETWEEN LOCATION.LATITUDE - (RANGELIMIT * 1.1508/60)
AND LOCATION.LATITUDE + (RANGELIMIT * 1.1508/60)