2013-10-02 1 views
1

Использование Rails 3.2, Ruby 1.9, geocoder gem. Следующий запрос у меня в контроллере:Ruby Geocoder nearbys медленный

# 1500+ms to load 
nearby_shops = (current_shop.nearbys(10, :order => 'overall_rating DESC') 
.where(:shop_type => shop_type).includes(:photos, :active_property_list => 
:hotel_image_lists).limit(5)) 

# SQL 
Shop Load (4045.6ms) SELECT shops.*, 3958.755864232 * 2 * ASIN(SQRT(POWER(
SIN((36.111927 - shops.lat) * PI()/180/2), 2) + COS(36.111927 * PI() 
/180) * COS(shops.lat * PI()/180) * POWER(SIN((-115.171229 - shops.lng) 
* PI()/180/2), 2))) AS distance, CAST(DEGREES(ATAN2(RADIANS(shops.lng 
- -115.171229), RADIANS(shops.lat - 36.111927))) + 360 AS decimal) % 360 AS 
bearing FROM `shops` WHERE `shops`.`shop_type` = 'food' AND (shops.lat BETWEEN 
35.96719521688915 AND 36.25665878311085 AND shops.lng BETWEEN 
-115.3503819353204 AND -114.9920760646796 AND 3958.755864232 * 2 * 
ASIN(SQRT(POWER(SIN((36.111927 - shops.lat) * PI()/180/2), 2) + 
COS(36.111927 * PI()/180) * COS(shops.lat * PI()/180) * POWER(SIN((
-115.171229 - shops.lng) * PI()/180/2), 2))) <= 10 AND shops.id != 85155) 
ORDER BY overall_rating DESC LIMIT 5 
- shops.lat) * PI()/180/2), 2) + COS(48.8582411618 * PI()/180) * 
COS(shops.lat * PI()/180) * POWER(SIN((2.2945044899 - shops.lng) * PI()/
180/2), 2))) <= 100 AND shops.id != 517) ORDER BY distance ASC LIMIT 25 
OFFSET 0 

Проблема заключается в nearbys, которая делает расчет на longitude и latitude. Я уже добавил индексы в столбцы longitude и latitude, но это ничего не улучшает.

Как я могу улучшить это?

P/S: Я удалил несвязанные условия, которые не влияют на скорость запроса.

+0

есть ли указатель на 'shop_type'? – Kyle

+0

@Kyle Да, уже. – Victor

+0

У меня очень похожий запрос, который работает в 98.4ms под Postgres 9.3. Какую базу данных вы используете? –

ответ

0

Это может быть не самое точное или изящное решение, но почему бы не просто немного выдумать математику. Вы можете написать выберите пункт, который сделал что-то вроде этого:

.select(["id, name, 69.0975851*sqrt(POWER(shops.lat-?,2) + COS(?*PI()/180)*POWER(shops.lon-?,2)) AS DISTANCE", loc.lat, loc.lat, loc.lon]) 

Вы действительно не должны использовать эту волосатую формулу большой круг, если вы просто имеем дело с маленькими (< 500 миль) расстояния. В итоге вы получите одинаковые ~ почти ~ ответы за долю вычислительной стоимости.