##Review ###DB Indexing
- Just like an index at the start of a book.
- Makes it easier to look for a specific record, because specific columns are catalogued.
create table :fans do |t|
t.string :name
t.references :backstreet_boy, :index => true
end###Partials
- Remember to render by collection when possible:
= render :partial => 'bboy_fan', :collection => bboy.fans
# renders _fan.haml
= render bboy.fans##The Problem: N+1
BackstreetBoy.all.each do |bboy|
puts bboy.fans.first.name
endSELECT * FROM backstreet_boys
SELECT * FROM fans WHERE backstreet_boy_id = 1 LIMIT 1
SELECT * FROM fans WHERE backstreet_boy_id = 2 LIMIT 1
SELECT * FROM fans WHERE backstreet_boy_id = 3 LIMIT 1
SELECT * FROM fans WHERE backstreet_boy_id = 4 LIMIT 1
SELECT * FROM fans WHERE backstreet_boy_id = 5 LIMIT 1eager_loadcreates one big query.
BackstreetBoy.eager_load(:fans).each do |bboy|
puts bboy.fans.first.name
endSELECT "backstreet_boys"."id" AS t0_r0, "backstreet_boys"."name" AS t0_r1, "fans"."id" AS t1_r0, "fans"."name" AS t1_r1 LEFT OUTER JOIN "backstreet_boys_fans" ON "backstreet_boys_fans"."backstreet_boy_id" = "backstreet_boys"."id" LEFT OUTER JOIN "fans" ON "fans"."id" = "backstreet_boys_fans"."fan_id" WHERE "backstreet_boys"."id"- This is good for queries that span multiple associations.
preloadperforms separate queries per association.
BackstreetBoy.preload(:fans).each do |bboy|
puts bboy.fans.first.name
endSELECT * FROM backstreet_boys WHERE "backstreet_boy_id" IN (1, 2, 3, 4, 5)
SELECT * FROM fans WHERE "fans"."id" IN (1, 2, 3, 4, 5, 6, 7, 8 ,9 ,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)- This is good for queries that span only a few associations.
- Using
preloadand subsequently chaining a condition afterwards will yield an error
BackstreetBoy.preload(:fans).where(:fans => {:name => 'Jomelina'})- Loading the association table separately doesn't
JOINthe 2 tables together.
- Use
eager_loadinstead.
includesdecides when to useeager_loadorpreload.- You may want to force
eager_loadfor valid queries that handle several associations.
eager_load-ing/includes-ing than one HABTM association of the same model will cause weird things to happen to the query.
- Use a combination of
eager_loadandpreload.
##4. Caching on your .rb file, set:
config.action_controller.perform_caching = true
# :file_store, :memory_store, :mem_cache_store
config.cache_store = :file_store, '/tmp/backstreet_cache'@bboy = BackstreetBoy.all
- Manually/Directly store data in the cache store
Rails.cache.fetch('nick_carters_biggest_fan') { 'James' }
=> "James"
Rails.cache.fetch('nick_carters_biggest_fan')
=> "James"- Each partial takes roughly 0.1ms to render. Fast? I think not.
- Imagine if you had over 9000 records!?.
- cache "bboy_fans-#{bboy.id}" do
= render :partial => 'bboy_fan', :collection => bboy.fansWrite:
Exist fragment? views/bboy_fans-2 (1.6ms)
Write fragment views/bboy_fans-2 (0.9ms)
Read:
Exist fragment? views/bboy_fans-2 (0.6ms)
Read fragment views/bboy_fans-2 (0.0ms)
- Expire fragments when changes occur:
expire_fragment("bboy_fans-#{@fan.bboy.id}")
- Nested fragments
- cache "bboy_fans-#{bboy.id}" do
- bboy.fans.each do |fan|
- cache "fan-#{fan.id}" do
= render :partial => 'bboy_fan', :locals => {:fan => fan}@bramirez on using memcached as an alternative cache store:
@bramirez's intro to fragment caching:
##Sources:
- Mamaya na later.