27.02.2013 Views

Rails%203%20In%20Action

Rails%203%20In%20Action

Rails%203%20In%20Action

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

446 CHAPTER 16 Basic performance enhancements<br />

This line would generate an SQL query like this:<br />

SELECT "tickets".* FROM "tickets"<br />

INNER JOIN "tags_tickets" ON "tags_tickets"."ticket_id" = "tickets"."id"<br />

INNER JOIN "tags" ON "tags"."id" = "tags_tickets"."tag_id"<br />

WHERE ("tickets".project_id = 1)<br />

The INNER JOIN parts of the query here mean that it will find all records in the<br />

tickets table that have tags only. It will also return a ticket record for every tag that it<br />

has, so if one ticket has three tags it will return three tickets. This is somewhat of a<br />

problem, given that you’re going to want to display all tickets regardless of if they are<br />

tagged or not, and you definitely don’t want three of them appearing when only one<br />

should.<br />

To fix this, use join’s brother includes, switching the line in the show action to<br />

this:<br />

@tickets = @project.tickets.includes(:tags).page(params[:page])<br />

When you refresh the page, Rails will generate two queries this time around:<br />

SELECT "tickets".* FROM "tickets"<br />

WHERE ("tickets".project_id = 1)<br />

LIMIT 50<br />

OFFSET 0<br />

SELECT "tags".*, t0.ticket_id as the_parent_record_id FROM "tags"<br />

INNER JOIN "tags_tickets" t0 ON "tags".id = t0.tag_id<br />

WHERE (t0.ticket_id IN (1,2,[...],49,50))<br />

Rails has run the query to find all the tickets first, then another query to gather all the<br />

tags for all the selected tickets as the second query. This query doesn’t care if tickets<br />

have tags or not, it will still fetch them.<br />

Here you’ve seen a way to cause an N+1 query and how to stop it from happening.<br />

You can remove the from app/views/projects/show.html.erb now,<br />

because you’re done with this experiment.<br />

This is just one way your database can be slow. Another is more insidious. It creeps<br />

in slowly over months of the application seemingly running fine and makes it progressively<br />

slower and slower. The problem is a lack of database indexes, and it affects many<br />

Rails applications even today.<br />

16.2.2 Database indexes<br />

Database indexes aren’t a Rails feature, they’re a feature of your own database that<br />

can greatly improve its performance when used correctly. The absence of database<br />

indexes may not seem like a problem immediately, but when you’re dealing with<br />

larger datasets it becomes more and more of a problem. Take for example if you had<br />

10,000 tickets with 2,300 of them belonging to Project A. To find all the tickets for<br />

Project A, your database sans indexes would have to do a full table scan, searching<br />

through each ticket and determining if it belonged to Project A or not. That’s a problem,<br />

because the more records you have, the longer this scan is going to take.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!