2013-02-27 50 views
2

Rails 3.2。我有以下幾點:在我log,最後3行與ID 26,23店優化Rails中的熱切加載

# city.rb 
class City < ActiveRecord::Base 
    has_many :zones, :dependent => :destroy 
end 

# zone.rb 
class Zone < ActiveRecord::Base 
    belongs_to :city 
    has_many :zone_shops, :dependent => :destroy 
    has_many :shops, :through => :zone_shops 
end 

# zone_shop.rb 
class ZoneShop < ActiveRecord::Base 
    belongs_to :zone 
    belongs_to :shop 
end 

# shop.rb 
class Shop < ActiveRecord::Base 
end 

# cities_controller.rb 
def show 
    @trip = City.find(params[:id], :include => [:user, :zones => [:shops]]) 
    @zones = @trip.zones.order("position") 

    # List out all shops for the trip 
    shops_list_array = [] 
    @zones.each do |zone, i| 
    zone.shops.each do |shop| 
     shops_list_array << shop.name 
    end 
    end 
    @shops_list = shops_list_array.join(', ') 
end 

# development.log 
    City Load (0.3ms) SELECT `cities`.* FROM `cities` WHERE `cities`.`id` = 1 LIMIT 1 
    Zone Load (0.3ms) SELECT `zones`.* FROM `zones` WHERE `zones`.`trip_id` IN (1) ORDER BY position asc 
    ZoneShop Load (0.3ms) SELECT `zone_shops`.* FROM `zone_shops` WHERE `zone_shops`.`zone_id` IN (26, 23, 22) ORDER BY position asc 
    Shop Load (0.5ms) SELECT `shops`.* FROM `shops` WHERE `shops`.`id` IN (8, 7, 1, 9) 
    Zone Load (0.5ms) SELECT `zones`.* FROM `zones` WHERE `zones`.`trip_id` = 1 ORDER BY position asc, position 
    Shop Load (0.5ms) SELECT `shops`.* FROM `shops` INNER JOIN `zone_shops` ON `shops`.`id` = `zone_shops`.`spot_id` WHERE `zone_shops`.`zone_id` = 26 
    Shop Load (0.6ms) SELECT `shops`.* FROM `shops` INNER JOIN `zone_shops` ON `shops`.`id` = `zone_shops`.`spot_id` WHERE `zone_shops`.`zone_id` = 23 
    Shop Load (0.4ms) SELECT `shops`.* FROM `shops` INNER JOIN `zone_shops` ON `shops`.`id` = `zone_shops`.`spot_id` WHERE `zone_shops`.`zone_id` = 22 

通知,22是多餘的。我應該如何重寫我的cities_controller.rb以減少對系統的查詢?

非常感謝。

回答

2
@zones = @trip.zones.includes(:shops).order("position") 

這種渴望,加載商店的關聯,並應elimitate造成zone.shops.each

對於N + 1個查詢問題更多的信息,看看Ruby on Rails Guide section 12 on Eager Loading associations,這也是由@Benjamin M

+0

Btw :':include => ... [:shops]])''''''''''''''''''''''''''''''''''''''''''因爲include的作用域是'@ trip',但是你正在循環'@ zones', '包括()'在 – emrass 2013-02-27 16:25:55

+0

您的解決方案爲以下項目創建緩存版本:** ZoneShop載入(0.3ms)SELECT'zone_shops'。*從'zone_shops'在哪裏'zone_shops'.'zone_id' IN(26,23,22)令(8,7,1,9)**,這可以正常工作。只是一個問題,是否有可能完全消除緩存? – Victor 2013-02-27 16:28:01

+0

你會如何改寫'show'? – Victor 2013-02-27 16:29:24

0

我建議這個

zone.shops.each do |shop| 
    shops_list_array << shop.name 
end 

產生日誌的最後3行。這意味着:您目前在數據庫中只有一個zone。如果你在那裏放置更多的區域,你會在日誌中獲得更多的Zone Load條目。

的問題顯然是Rails的each方法,這會觸發延遲加載:

@zones.each do |zone, i| 
    ... 

的解決方案取決於您的需求,但我建議你閱讀Rails的一切都渴望加載功能。 (這正是你的問題:each的事情)。你看它這裏:http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

這是很容易,簡短易懂:)

+0

鏈接是的,我知道這是'每條'線給我的問題。但我想知道是否有另一種方式來編寫它,以便最後3行不需要生成。因爲你會看到'商店'早已被查詢過。 – Victor 2013-02-27 15:51:19

+0

對不起,我誤解了你的問題。但也許這是你的解決方案:http://stackoverflow.com/a/5982057/1321564 ...似乎渴望加載'has_many通過:'有時要明確強制加入才能正常工作;) – 2013-02-27 16:03:01