开发者

Performances on rails

开发者 https://www.devze.com 2023-04-12 22:17 出处:网络
I have a problem of performances with rails. When i do an ajax call to a controller like this : def test

I have a problem of performances with rails. When i do an ajax call to a controller like this :

def test
    @hotels = Hotel.all
    render :json => ['hotels' => @hotels ], :include=> [:country, :city]
end

It takes maybe 2-5 seconds to finish. I only have 40 hotels in my database. I think it very long... for example, the same request on Django will take 400ms

Did i forgot to configure well my environement?

I use Rails entreprise version and passenger.

EDIT : My log file :

     Started GET "/hotels/test.json" for 172.16.81.1 at Wed Oct 12 22:11:06 +0200 2011
    [paperclip] Duplicate URL for image with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in HotelImage class
    [paperclip] Duplicate URL for thumbnail with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Hotel class
    [paperclip] Duplicate URL for map with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Hotel class
    [paperclip] Duplicate URL for thumbnail with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in DestinationAlbumPhoto class
    [paperclip] Duplicate URL for map with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Destination class
    [pa开发者_运维知识库perclip] Duplicate URL for image with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Continent class
    [paperclip] Duplicate URL for thumbnail with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Destination class
    [paperclip] Duplicate URL for image with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Event class
    [paperclip] Duplicate URL for thumbnail with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in HotelAlbumPhoto class
    [paperclip] Duplicate URL for map with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Event class
      Processing by HotelController#test as JSON
      [1m[36mHotel Load (0.2ms)[0m  [1mSELECT `hotels`.* FROM `hotels`[0m
      [1m[35mCountry Load (0.1ms)[0m  SELECT `countries`.* FROM `countries` WHERE (`countries`.`id` = 3)
      [1m[36mCity Load (0.1ms)[0m  [1mSELECT `cities`.* FROM `cities` WHERE (`cities`.`id` = 2)[0m
    Completed 200 OK in 405ms (Views: 366.1ms | ActiveRecord: 0.3ms)

It's writen 405ms but firefox tell me 3,7sec.

My hotel model :

class Hotel < ActiveRecord::Base
  cattr_reader :per_page
  @@per_page = 16

  belongs_to :hotel_type
  belongs_to :hotel_theme
  belongs_to :country
  belongs_to :city
  belongs_to :destination
  belongs_to :continent

  has_many :hotel_comments, :dependent => :destroy

  has_many :hotel_album_photos, :dependent => :destroy

  has_many :hotel_activity_values

  has_many :hotel_service_values

  accepts_nested_attributes_for :hotel_album_photos

  has_attached_file :thumbnail, :styles => { :medium => "300x300>", :thumb => "191x134>"} , :default_url => '/images/default/missing.png' 
  has_attached_file :map, :styles => { :medium => "300x300>", :thumb => "191x134>"} , :default_url => '/images/default/missing.png' 

  scope :country, lambda { |country_id|
     self.scoped.where('country_id IN ( ? )', country_id) unless country_id.blank?
  }

  scope :selection, lambda { |selection|
     self.scoped.where('selection = ? ', 1) unless selection.blank?
  }

  scope :city, lambda { |city_id|
      self.scoped.where('city_id IN ( ? )', city_id) unless city_id.blank?
  }

  scope :hoteltype, lambda { |type|
      self.scoped.where('hotel_type_id IN ( ? )', type) unless type.blank?
   }

  scope :theme, lambda { |theme|
      self.scoped.where('hotel_theme_id IN ( ? )', theme) unless theme.blank?
   }

  scope :prices, lambda { |prices|
      condition = []
      prices.each do |price|
        pricesArray = price.split('-')
        condition.push '(price BETWEEN ' + pricesArray[0] + ' AND ' + pricesArray[1] + ')'
      end
      self.scoped.where(condition.join(' OR ')) 
   }

   scope :order_by_price, lambda { |direction|
     self.scoped.order('price ' + direction)
   }

   scope :order_by_rate, lambda { |rate|
     self.scoped.order('global_rate ' + rate)
   }

   scope :services, lambda { |services|
      {:joins => [:hotel_service_values ]  , :conditions => { :hotel_service_values => {:hotel_service_id  => services}}}
   }

  scope :limiter, lambda { |limiter|
      self.scoped.limit(limiter)
   }

end

Thank you for help.


Looking at you code, my guess is you have a simple "N+1" problem.

Namely you load @hotels into an array, but when you come to produce the json you load the country and cityfor eachhotel.

So for your 40 hotels, you have to do a total of 81 database queries.

This can simply be improved by doing an include when you load.

In the old style

Hotel.all(:include => [:country, :city])

In Rails 3 style

Hotel.includes(:country, :city).all

With this change you should only be making 3 database calls in total.

See the Rails Guide on Eager Loading for more info.


Looking at the Log, Rails seems to be thinking it got the response out in 405 ms. This leaves rest of the stack to consider:

  1. Rails (✓)
  2. Passenger
  3. Apache
  4. Network
  5. DNS resolving
  6. Browser rendering

First, see how other browsers fare. I have seen occasional issues on one of our (non-rails) sites with Firefox, while Webkit-based browsers (Safari, Chrome) are OK. Maybe Firefox chokes up for some reason (e.g. DNS resolving issues or something other).

If all browsers are the same (or especially, if Firefox is the culprit), then open Firebug and take look at the Net tab, especially the XHR (AJAX) tab under that. Hover your mouse over one of the queries' time bar to see breakdown of where the time went: DNS, Connecting, Sending, Waiting, Receiving.

If Firebug indicates that the time is spent on the request itself (Sending, Waiting, Receiving), then take a look at Apache log - turn on CustomLog time reporting (add %D - see documentation) and see how long Apache thinks these requests take.

This should narrow down your problem to further analyze causes.


I was using VMWare to make my web server running. My performances problems was about that. I find my solution here :

Webrick is very slow to respond. How to speed it up?

0

精彩评论

暂无评论...
验证码 换一张
取 消