레일즈 애플리케이션에서 geokit (acts_as_mappable)을 사용하고 있습니다. 많은 수의 모델이있을 때 방사형 또는 경계 검색 성능이 크게 떨어졌습니다 (1-2million으로 시도했지만 문제는 의심 할 여지가 없습니다) 이것보다).mysql이 내 인덱스를 사용하고 있는지 여부와 geokit의 성능을 향상시킬 수 있습니까?
Geokit은 테이블의 위도와 경도 (위도와 경도)를 기반으로 모든 계산을 수행합니다. 성능을 향상시키기 위해 일반적으로 위도와 경도에 결합 된 인덱스를 사용하여 성능을 향상시키려는 의도로 경계 상자에 'where'절을 추가합니다. 그러나 여전히 많은 수의 모델로 인해 매우 느리며 테두리 상자 절이 훨씬 더 도움이 될 것 같습니다.
내 질문에, 거기에 방법을 더 나은 결합 된 위도/lng 인덱스를 사용하거나 그렇지 않으면 geokit SQL 쿼리의 성능을 향상시킬 수 있습니까? 또는 lat/lng에 대한 조합 된 인덱스가 더 도움이 될 수 있습니까?
편집 : 지금 레일이 작업을 가지고 더 상세하게 솔루션을 작성했습니다 here 배경 예를 들어
,이 쿼리는 주어진 10 마일 이내에 모든 장소를 찾아
더 포인트. (내가 얼마나 많은 결과가 돌아 왔는지를 결정하기 위해 .length를 추가했다. geokit에서 이것을 말하는 더 좋은 방법이 있지만 좀 더 일반적인 SQL 쿼리를 강제하고 싶다.)
Place.find(:all,:origin=>latlng,:within=>10).length
Mac mini에는 약 14 초가 걸립니다. 여기에 그래서 MySQL은 87,554 결과에서 장소의 수는 1,135하더라도 행을 검사하는 계획을
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 |
+----+-------------+--------+-------+-----------------------------+-----------------------------+---------+------+-------+----------+-------------+
설명이다 (실제로 경계 상자에 자릿수 단지 1323)입니다. ([: 위도 : LNG] 장소 레일 이주 add_index 등으로 이루어진다)
| 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
감사합니다 - 그것은 훨씬 더 잘 작동하고 나는 그것을 밖으로 시도 할 것 같은데. 공간을 사용하지 않고 현재 쿼리를 향상시킬 수있는 방법이 있습니까 (geokit은 현재 mysql spatial stuff를 사용하지 않습니다)? 이 쿼리를 실행하면 흥미롭게도 – frankodwyer
WHERE ((places.lat> 51.3373601471464 AND places.lat <51.6264998528536)); 42078 행만 반환합니다! 그래서 mysql이 그 부분을 잘 수행하지 못하는 것 같습니다. – frankodwyer