I am newbie in Rails 3.
I'm trying to find out why my page is loaded so much slow.
I am in development mode (but in production mode there is the sane picture)
There is a log:
Started GET "/inv/claims?locale=uk" for 127.0.0.1 at 2012-05-07 14:36:24 +0300
Processing by ClaimsController#index as HTML
Parameters: {"locale"=>"uk", "property"=>"inv"}
Rendered shared/_apps_list.html.erb (0.0ms)
Rendered shared/_apps_list.html.erb (0.0ms)
Rendered shared/_apps_list.html.erb (15.6ms)
Rendered shared/_apps_list.html.erb (0.0ms)
Rendered shared/_apps_list.html.erb (0.0ms)
Rendered shared/_apps_list.html.erb (0.0ms)
Rendered shared/_apps_list.html.erb (15.6ms)
Rendered shared/_apps_list.html.erb (0.0ms)
Rendered shared/_apps_list.html.erb (0.0ms)
Rendered shared/_apps_list.html.erb (0.0ms)
Rendered shared/_apps_lists.html.erb (31.3ms)
Rendered claims/index.html.erb within layouts/application (46.9ms)
Completed 200 OK in 1594ms (Views: 46.9ms | ActiveRecord: 0.0ms)
Total amount of time is 1594ms
First question: Is it really slow?
1594 - 46.9 = *1547*ms - it's a time that my page spends for some logic (not for rendering and querying).
Second question: Is the logic of application bad in that case (1547ms)?
I try to make pagination
My page logic:
I have a folder structure:
/myfolder/1/application.xml (size of any application.xml about 5Kb)
/myfolder/2/application.xml
/myfolder/3/application.xml
/myfolder/4/application.xml
/myfolder/5/application.xml
...
/folder/50/application.xml
I'm doing...
1) I am getting such information about each folder in myfolder (myfolder/1/, myfolder/2/...): folder creation or change date. I store that information in Hash.
2) Sort getting on step 1) Hash by date of creation or change
3) Getting slice of Hash using start id and step. Saving it in new Hash.
4) Iterating through Hash from step 3. For every entry reading application.xml and parsing it to hash using doc_hash = Hash.from_xml(Nokogiri::XML(f, &:noblanks).to_xml
Yes. That's a second and a half to process a page. It's too slow.
It looks like there must be some strange logic error somewhere. Spending over a second in non-activerecord, non-view processing is way too long.
I'd look pretty deeply at any loops you have and try to understand what's happening at that level.
Related
In my model, I check if a Sudoku record exists in the database first before I either fetch it's solution or create it.
if Sudoku.exists?(puzzle: puzzle)
return Sudoku.find_by(puzzle: puzzle).solution
else
**solve it and save it into the db**
end
What is the difference from doing this:
if Sudoku.find_by(puzzle: puzzle)
return Sudoku.find_by(puzzle: puzzle).solution
else
**solve it and save it into the db**
end
Logs for exists?
Sudoku Exists (0.0ms) SELECT 1 AS one FROM "sudokus" WHERE "sudokus"."puzzle" = $1 LIMIT 1 [["puzzle", "390820700801500069020160403002096058935000602060752030703941000200037590019000347"]]
Sudoku Load (0.0ms) SELECT "sudokus".* FROM "sudokus" WHERE "sudokus"."puzzle" = $1 LIMIT 1 [["puzzle", "390820700801500069020160403002096058935000602060752030703941000200037590019000347"]]
Completed 200 OK in 8ms (Views: 0.2ms | ActiveRecord: 3.0ms)
Logs for find_by
Sudoku Load (0.0ms) SELECT "sudokus".* FROM "sudokus" WHERE "sudokus"."puzzle" = $1 LIMIT 1 [["puzzle", "390820700801500069020160403002096058935000602060752030703941000200037590019000347"]]
CACHE (0.0ms) SELECT "sudokus".* FROM "sudokus" WHERE "sudokus"."puzzle" = $1 LIMIT 1 [["puzzle", "390820700801500069020160403002096058935000602060752030703941000200037590019000347"]]
Completed 200 OK in 7ms (Views: 0.2ms | ActiveRecord: 2.0ms)
At first, I thought by doing two find_by it would hit the database twice, but then I see the CACHE. Does that mean Rails remember the previous query in the first find_by and is only hitting it once?
Why would I use exists? over find_by ?
Edit:
From advice, I'm using this now:
if sudoku = Sudoku.find_by(puzzle: puzzle)
return sudoku.solution
else
**solve it and save it into the db**
end
Rails wraps each controller action with a simple query cache. The CACHE in the logs does indicates that the query was served from the cache. If you were to run that code in the console you wouldn't get that caching (unless you explicitly set that up).
The difference query wise is that none of the fields of the object are fetched from the database. Aside from the network impact, depending on the query and the indices present, your database may be able to use a covering index (in a nutshell the index can be used to answer the query completely instead of the db using the index to find the data for the row)
On top of that rails doesn't construct an active record object from the result, you just get back true/false.
So exists? is faster. However it's pointless if you then call find_by straight after. You might as well call find_by once only.
So I've been using MongoDB (with the Mongoid Ruby Gem) for a while now, and as our app has grown I've noticed requests taking longer and longer as my data has grown, here is what a typical request for my app looks like, but it takes about 500ms, just for the DB stuff.
Nothing special here just some controller stuff:
Started GET "/cities/san-francisco?date_range=past_week" for 127.0.0.1 at 2011-11-15 11:13:04 -0800
Processing by CitiesController#show as HTML
Parameters: {"date_range"=>"past_week", "id"=>"san-francisco"}
Then the queries run, but what I don't understand is that for every query that runs it performs a MONGODB dashboard_development['system.namespaces'].find({}) before actually running it! Why?
MONGODB dashboard_development['system.namespaces'].find({})
MONGODB dashboard_development['users'].find({:_id=>BSON::ObjectId('4e80e0090f6d2e306f000001')})
MONGODB dashboard_development['system.namespaces'].find({})
MONGODB dashboard_development['cities'].find({:slug=>"san-francisco"})
MONGODB dashboard_development['system.namespaces'].find({})
MONGODB dashboard_development['accounts'].find({:_id=>BSON::ObjectId('4e80e0090f6d2e306f000002')})
MONGODB dashboard_development['system.namespaces'].find({})
MONGODB dashboard_development['neighborhoods'].find({"city_id"=>BSON::ObjectId('4e80e00a0f6d2e306f000005')})
Then the views get rendered, they are pretty slow too... but that is a seperate problem all together, I'll address that at another time.
Rendered cities/_title_and_scope.html.erb (109.3ms)
Rendered application/_dropdown.html.erb (0.1ms)
Rendered application/_date_range_selector.html.erb (6.2ms)
Rendered cities/show.html.erb within layouts/application (122.7ms)
Rendered application/_user_dropdown.html.erb (0.9ms)
Rendered application/_main_navigation.html.erb (5.8ms)
So minus the views the request took about 500ms, thats too long for a really simple query, additionally the app is going to grow and that time is going to grow as well. Also this example is faster than the requests usually take, sometimes it takes 1000ms or more!
Completed 200 OK in 628ms (Views: 144.9ms)
Additionally I wanted to ask what fields are most appropriate for indexes? Maybe this is my problem, as I'm not really using them at all. Any help understanding this would be really really appreciated. Thanks!
You need to use indexes -- otherwise, your mongo queries are executing what is best described as a full table scan. It is loading the entirety of your collection's json documents into memory and then evaluating each one to determine if it should be including in the response.
Strings, Date, Numbers can all be used as index -- the trick is, have an index on each attribute you are doing a "where" on.
You can turn off table-scans in your mongo config to help find table scans and destroy them!
One method of debugging within the Controllers I have learnt from Django is to actually print out variables within the controllers itself. However, I realize that this method is not as practical in rails as the default rails webserver is pretty verbose and it's making me difficult to trace.
FYI I read about the rails debugging page but most of those debug techniques exist in the VIEW layer (like <% #myvar.debug %>). I want to be able to see the state of vars inside the controllers and I don't want to use the rails debugger as it's kind of an overkill for something so simple.
My question is: is there a variable that I can set to reduce statements like those below from being produced at each page serve?
Started POST "/submissions" for 127.0.0.1 at 2011-06-02 02:35:38 -0400
Processing by SubmissionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"U+I2mSfCRFvOyT/L82TTzsVRVJQuJbB+X3SaMWr/IM4=", "submission"=>{"url"=>"http://wasdvasd.com", "receiver_id"=>"1", "comment"=>"asdvasdvasdv"}, "commit"=>"Create Submission"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Link Load (0.1ms) SELECT "links".* FROM "links" WHERE "links"."url" = 'http://wasdvasd.com' LIMIT 1
AREL (0.3ms) INSERT INTO "links" ("url", "created_at", "updated_at") VALUES ('http://wasdvasd.com', '2011-06-02 06:35:38.399463', '2011-06-02 06:35:38.399463')
AREL (0.2ms) INSERT INTO "submissions" ("link_id", "author_id", "receiver_id", "comment", "visited", "created_at", "updated_at") VALUES (5, 1, 1, 'asdvasdvasdv', NULL, '2011-06-02 06:35:38.402094', '2011-06-02 06:35:38.402094')
Redirected to http://localhost:3000/submissions
Completed 302 Found in 244ms
You should be able to change the logging level in your config/environments/*.rb files.
See: http://guides.rubyonrails.org/debugging_rails_applications.html#log-levels for the different log levels.
In a Rails controller action I call
#grid = Grid.find(params[:id], :include => [:grid_properties, :grid_entities => [:entity => :properties]])
Unfortunately it takes really long. Benchmark.realtime (in development mode) tells me 1.8812830448150635, so about 2 seconds (Rails 3.0.7, Postgres 8.4).
When turning on the SQL logging I get the following for this line of code:
Grid Load (0.9ms) SELECT "grids".* FROM "grids" WHERE "grids"."id" = 2 LIMIT 1
GridProperty Load (2.5ms) SELECT "grid_properties".* FROM "grid_properties" WHERE ("grid_properties".grid_id = 2) ORDER BY row_order
GridEntity Load (1.3ms) SELECT "grid_entities".* FROM "grid_entities" WHERE ("grid_entities".grid_id = 2) ORDER BY row_order
Entity Load (3.0ms) SELECT "entities".* FROM "entities" WHERE ("entities"."id" IN (28,7,3,6,25,11,2,12))
Property Load (6.4ms) SELECT "properties".* FROM "properties" WHERE ("properties".entity_id IN (28,7,3,6,25,11,2,12))
Every database access seems to be in the low millisecond range. Why does it take so long in the end?
I guess that the time is spent on creating the object by Ruby. How many Properties are in that Grid? The time of 'SELECT FROM properties' looks relatively high.
You could further investigate the problem, if you have some functions where you could place checkpoints - logger.debug "CHECKPOINT: #{Time.now} #{caller(0).first}"
Do you have any 'on_load' callbacks, maybe?
My application.html.erb is a classic file with the <%= yield %> statement. The expected would be if I went to domain.com/controller/action that it yields to the view in the appropriate directory. Instead, it's pulling up just the view (the correct view, but without the application wrapper). (There's no other layouts other than application)
This is my second rails application. The other one went smoothly, but this one is giving me one problem after another. I rtfm'd and googled and came up with nothing. I even rebooted webrick, though I didn't restart apache (proxypass to webrick), as I thought that overkill. Not to mention we host some low-volume websites.
The strangest thing is, when I call the root ie: domain.com it calls application.html.erb and yields to the home view.
I did use scaffolding, but it was my understanding that calling script/generate scaffold simply builds files and doesn't configure anything except routes. Which I already fixed.
Things I thought might help answer question. Let me know if you need more.
Devel logs where it's obvious that layouts application isn't loading:
domain.com
Processing HomeController#index (for 24.20.194.187 at 2009-09-03 15:24:15) [GET]
Parameters: {"action"=>"index", "controller"=>"home"}
ESC[4;35;1mCompany Columns (2.6ms)ESC[0m ESC[0mSHOW FIELDS FROM `companies`ESC[0m
ESC[4;36;1mCompany Load (0.4ms)ESC[0m ESC[0;1mSELECT * FROM `companies` WHERE (`companies`.`subdomain` = 'slate') LIMIT 1ESC[0m
Rendering template within layouts/application
Rendering home/index
ESC[4;35;1mUser Columns (2.6ms)ESC[0m ESC[0mSHOW FIELDS FROM `users`ESC[0m
ESC[4;36;1mUser Load (0.4ms)ESC[0m ESC[0;1mSELECT * FROM `users` WHERE (`users`.`id` = '2') LIMIT 1ESC[0m
domain.com/users
Processing UsersController#index (for 24.20.194.187 at 2009-09-03 15:24:03) [GET]
Parameters: {"action"=>"index", "controller"=>"users"}
ESC[4;36;1mCompany Columns (2.6ms)ESC[0m ESC[0;1mSHOW FIELDS FROM `companies`ESC[0m
ESC[4;35;1mCompany Load (0.4ms)ESC[0m ESC[0mSELECT * FROM `companies` WHERE (`companies`.`subdomain` = 'slate') LIMIT 1ESC[0m
ESC[4;36;1mUser Columns (2.7ms)ESC[0m ESC[0;1mSHOW FIELDS FROM `users`ESC[0m
ESC[4;35;1mUser Load (0.4ms)ESC[0m ESC[0mSELECT * FROM `users` ESC[0m
Rendering users/index
ESC[4;36;1mSQL (0.2ms)ESC[0m ESC[0;1mSET NAMES 'utf8'ESC[0m
ESC[4;35;1mSQL (0.2ms)ESC[0m ESC[0mSET SQL_AUTO_IS_NULL=0ESC[0m
application.html.erb [edited element contents]:
Oh right. less than greater than. suffice it to say, it has the html, head, and body tags, with a <%= yield %> statement.
First confirm that the only file in views/layouts is application.html.erb, then double check your UsersController and make sure that any line specifying the layout is removed.