我在rails應用程序中使用geokit(acts_as_mappable),並且在有大量模型時(我嘗試使用1-2百萬個但是問題無疑在早期開始使用)時,徑向或邊界搜索的性能顯着降低比這個)。mysql是否使用我的索引,並且可以改進geokit的性能?
Geokit根據表格(緯度和經度)中的lat和lng列進行所有計算。爲了提高性能,geokit通常會添加一個bounding box'where'子句,目的是在經度和緯度上使用組合索引來提高性能。但是,對於大量模型來說,它仍然非常慢,而且在我看來,邊界框子句應該比它更有幫助。
所以我的問題是,有沒有辦法讓mysql更好地使用組合的經緯度/指數或以其他方式改善geokit sql查詢的性能?或者,lat/lng的組合索引可以更有幫助嗎?
編輯:我有這個工作與軌現在更詳細的書面解決了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)。
以上是關於索引的統計信息(其與導軌遷移add_index製成:地方,[: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 | |
也不它似乎與到三角函數的計算,因爲這樣做類似的查詢的邊框導致更簡單的查詢,但它執行同樣糟糕:
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 |
+----+-------------+--------+-------+-----------------------------+-----------------------------+---------+------+-------+----------+-------------+
這很有趣 - 在那種情況下應該有什麼樣的索引? – frankodwyer 2009-08-26 11:23:12
謝謝 - 這聽起來像它會工作得更好,我會嘗試一下。還有一種方法可以在不使用空間的情況下改進當前查詢(因爲geokit目前不使用mysql空間)。 – frankodwyer 2009-08-26 11:32:04
有趣的是,如果我運行這個查詢SELECT * FROM'places' WHERE((places.lat> 51.3373601471464 AND places.lat <51.6264998528536));它只返回42078行!所以它看起來像MySQL也沒有很好的工作。 – frankodwyer 2009-08-26 11:35:56