jav*_*der 5 mysql database indexing geospatial latitude-longitude
我有一个遗留的innodb表列表,其中包含具有纬度/经度的业务.给定一个输入经/纬度(以下51.2167/4.41667),查询到的接近(千米)的顺序返回第一激活,激活,未删除30家企业.与帐户表的连接用于检查列表的有效性.
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;
Run Code Online (Sandbox Code Playgroud)
表列表和帐户每个包含超过50,000行,但查询仍然需要24秒才能运行.没有订单,需要17秒.
我已经尝试在活动,已批准,已删除,已启用时设置一些索引.我可以重写查询或添加某些索引来有效地执行此查询 - 而无需更改表结构吗?
+----+-------------+---------+-------------+-------------------------------------------------------------------------------------------------+-----------------------------------------------------------------+---------+------------------------+------+--------------------------------------------------------------------------------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------------+-------------------------------------------------------------------------------------------------+-----------------------------------------------------------------+---------+------------------------+------+--------------------------------------------------------------------------------------------------------------------------------+
| 1 | SIMPLE | listing | index_merge | FKB4DC521D9306A80C,listing_active,listing_approved,listing_enabled,listing_deleted,index_test_1 | listing_active,listing_approved,listing_enabled,listing_deleted | 1,1,1,1 | NULL | 3392 | Using intersect(listing_active,listing_approved,listing_enabled,listing_deleted); Using where; Using temporary; Using filesort |
| 1 | SIMPLE | account | eq_ref | PRIMARY,account_enabled,account_activated_by_user,index_test_2 | PRIMARY | 8 | ctm.listing.account_id | 1 | Using where |
+----+-------------+---------+-------------+-------------------------------------------------------------------------------------------------+-----------------------------------------------------------------+---------+------------------------+------+--------------------------------------------------------------------------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
任何帮助是极大的赞赏.
这需要很长时间,因为您的查询正在为50k行表中的每一行计算具有所有超越函数的大圆距离公式(当您包括排序时两次).
你能限制搜索的距离范围吗?您可能已经注意到,大多数商店查找器Web应用程序都有一个下拉菜单项,可以选择"5英里内","10英里内",等等.
如果可以这样做,则应该在搜索中添加WHERE子句,并通过在LATITUDE列上添加索引来对其进行优化.假设您使用RANGELIMIT值作为搜索范围限制,以英里为单位.
试试这个条款
WHERE LISTING.LATITUDE BETWEEN LOCATION.LATITUDE - (RANGELIMIT * 1.1508/60)
AND LOCATION.LATITUDE + (RANGELIMIT * 1.1508/60)
Run Code Online (Sandbox Code Playgroud)
这是因为海里几乎完全等于纬度的一分钟(1/60).1.1508因子将海里数转换为法定里程.
我建议的条款将使用纬度指数来缩小搜索范围,并且您将更频繁地计算大圆距离.
您还可以在经度上包含BETWEEN子句.但根据我的经验,只需在BETWEEN搜索范围内进行搜索,即可获得出色的效果.