mysql是否使用我的索引,是否可以改善geokit的性能?
作者:互联网
我在rails应用程序中使用了geokit(acts_as_mappable),并且当存在大量模型时,径向或边界搜索的性能会大幅下降(我已经尝试了1-2百万但是这个问题无疑会比这更早出现).
Geokit根据表格中的lat和lng列(纬度和经度)完成所有计算.为了提高性能,geokit通常会添加一个边界框’where’子句,目的是在纬度和经度上使用组合索引来提高性能.然而,对于大量模型来说,它仍然非常慢,而且在我看来,边界框子句应该比它更有帮助.
所以我的问题是,有没有办法让mysql更好地利用组合的lat / lng索引或以其他方式提高geokit sql查询的性能?或者,lat / lng的组合索引可以更有用吗?
编辑:我现在已经开始使用rails了,并且更详细地编写了解决方案here
更多背景
例如,此查询查找给定点10英里内的所有位置. (我添加.length只是为了确定返回多少结果 – 有更好的方法在geokit中说这个,但我想强制一个更典型的SQL查询).
Place.find(:all,:origin=>latlng,:within=>10).length
Mac mini需要大约14秒.这是解释计划
mysql> explain SELECT *, (ACOS(least(1,COS(0.898529183781244)*COS(-0.0157233221653665)*COS(RADIANS(places.lat))*COS(RADIANS(places.lng))+ -> COS(0.898529183781244)*SIN(-0.0157233221653665)*COS(RADIANS(places.lat))*SIN(RADIANS(places.lng))+ -> SIN(0.898529183781244)*SIN(RADIANS(places.lat))))*3963.19)
-> AS distance FROM `places` WHERE (((places.lat>51.3373601471464 AND places.lat<51.6264998528536 AND places.lng>-1.13302245886176 AND places.lng<-0.668737541138245)) AND ( (ACOS(least(1,COS(0.898529183781244)*COS(-0.0157233221653665)*COS(RADIANS(places.lat))*COS(RADIANS(places.lng))+
-> COS(0.898529183781244)*SIN(-0.0157233221653665)*COS(RADIANS(places.lat))*SIN(RADIANS(places.lng))+
-> SIN(0.898529183781244)*SIN(RADIANS(places.lat))))*3963.19)
-> <= 10))
-> ;
+----+-------------+--------+-------+-----------------------------+-----------------------------+---------+------+-------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+-------+-----------------------------+-----------------------------+---------+------+-------+----------+-------------+
| 1 | SIMPLE | places | range | index_places_on_lat_and_lng | index_places_on_lat_and_lng | 10 | NULL | 87554 | 100.00 | Using where |
+----+-------------+--------+-------+-----------------------------+-----------------------------+---------+------+-------+----------+-------------+
所以mysql正在检查87554行,即使结果中的位数是1135(实际上在边界框中的位数只有1323).
这些是索引上的统计信息(使用rails migration add_index:places,[:lat,:lng]):
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
| places | 1 | index_places_on_lat_and_lng | 2 | lng | A | 1373712 | NULL | NULL | YES | BTREE | |
它似乎也与trig计算无关,因为对边界框执行类似的查询会导致查询更简单,但它的执行效果也差不多:
Place.find(:all,:bounds=>GeoKit::Bounds.from_point_and_radius(latlng,10)).length
提供类似的解释计划:
mysql> explain SELECT * FROM `places` WHERE ((places.lat>51.3373601471464 AND places.lat<51.6264998528536 AND places.lng>-1.13302245886176 AND places.lng<-0.668737541138245)) ;
+----+-------------+--------+-------+-----------------------------+-----------------------------+---------+------+-------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+-------+-----------------------------+-----------------------------+---------+------+-------+----------+-------------+
| 1 | SIMPLE | places | range | index_places_on_lat_and_lng | index_places_on_lat_and_lng | 10 | NULL | 87554 | 100.00 | Using where |
+----+-------------+--------+-------+-----------------------------+-----------------------------+---------+------+-------+----------+-------------+
解决方法:
普通的B-Tree索引对于像这样的查询来说并不太好.
对于您的查询,范围访问方法用于以下条件:
places.lat > 51.3373601471464 AND places.lat < 51.6264998528536
,这甚至不考虑lon.
如果要使用空间能力,则应将场所保留为点,创建它们的SPATIAL索引并使用MBRContains过滤边界框:
ALTER TABLE places ADD place_point GEOMETRY
CREATE SPATIAL INDEX sx_places_points ON places (place_point)
UPDATE places
SET place_point = Point(lat, lon)
SELECT *
FROM places
WHERE MBRContains(LineString(Point(51.3373, -1.1330), Point(51.6264, -0.6687)), place_point)
AND -- do the fine filtering here
更新:
CREATE TABLE t_spatial (id INT NOT NULL, lat FLOAT NOT NULL, lon FLOAT NOT NULL, coord GEOMETRY) ENGINE=MyISAM;
INSERT
INTO t_spatial (id, lat, lon)
VALUES (1, 52.2532, 20.9778);
UPDATE t_spatial
SET coord = Point(lat, lon);
这在5.1.35中适用于我.
标签:mysql,sql-execution-plan,performance,geokit 来源: https://codeday.me/bug/20190701/1344440.html