Ruby/Rails syntax
  • Index
  • chap 1
  • chap 2
  • chap 3
  • chap 4
  • Enterprise Rails - big picture
  • Nokogiri
  • ActiveRecord - 進階功能
  • pack & unpack
  • performance
  • rails engine
  • jsonb / json / hstore
  • Deploy
  • Polymorphism/Polymorphic Associations
  • relationship
  • rvm / ENV
  • Auth
  • DB related
  • TODO N+1
  • SQL view
  • module
  • api + create-react-app
  • ONE_LINE
  • Delete & destroy association
Powered by GitBook
On this page
  • select, pluck
  • How long to build ActiveRecord models
  • Preload, Eagerload, Includes and Joins
  • Intention for eager loading
  • Too much query

Was this helpful?

performance

Previouspack & unpackNextrails engine

Last updated 5 years ago

Was this helpful?

select, pluck

pluck will load an array of column, and is faster than select.

select is ~10X slower than pluck, because of creating objects.

User.select(:id).to_a
# => User Load (0.9ms)  SELECT id FROM "users"
# => [#<User id: 12>, #<User id: 42>, #<User id: 1>, #<User id: 24>, #<User id: 200>, ...]
User.pluck(:id)
# => (0.9ms)  SELECT "users"."id" FROM "users"
# => [12, 42, 1, 24, 200, ..., 365]

User.pluck(:first_name, :last_name, :email)
# =>   (2.2ms)  SELECT "users"."first_name", "users"."last_name", "users"."email" FROM "users"
# => [[nil, nil, "jeff@gmail.com"], ['joe', nil, "joe.brown@gmail.com"], ["Edward", "Stanza", "ed@email.com"], ...]

How long to build ActiveRecord models

10.4ms for db query, but total 143ms for the whole process.

User.all.to_a
# => User Load (10.4ms)  SELECT "users".* FROM "users"
# => [#<User id: 263, ... >, #<User id: 264, ... >, #<User id: 265, ... >, ... ]

puts Benchmark.measure { User.all.to_a }
    user    system     total        real
0.143333  0.000000  0.143333 (  0.163123)

Preload, Eagerload, Includes and Joins

preload, eager_load, includes = eager loading (prevent n+1)

  1. Preload loads the association data in a separate query.

     User.preload(:posts).to_a
     # =>
     SELECT "users".* FROM "users"
     SELECT "posts".* FROM "posts"  WHERE "posts"."user_id" IN (1)

    Since preload always generates two sql, we can’t use posts table in where condition.

     User.preload(:posts).where("posts.desc='ruby is awesome'")
     # =>
     SQLite3::SQLException: no such column: posts.desc:
  2. eager_loading loads all association in a single query using LEFT OUTER JOIN.

     User.eager_load(:posts).to_a    
     # =>
     SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
            "posts"."title" AS t1_r1, "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
     FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
  3. Includes

    Behaves based on situations, intelligent!

    Blog.includes(:posts)
    # =>
    Blog Load (2.8ms)  SELECT "blogs".* FROM "blogs"
    Post Load (0.7ms)  SELECT "posts".* FROM "posts" WHERE "posts"."blog_id" IN (1, 2, 3)
    
    Blog.includes(:posts).where(name: 'Blog 1').where(posts: {title: 'Post 1-1'})
    # =>
    SQL (0.2ms)  SELECT "blogs"."id" AS t0_r0, "blogs"."name" AS t0_r1, "blogs"."author" AS t0_r2, "blogs"."created_at" AS t0_r3, "blogs"."updated_at" AS t0_r4, "posts"."id" AS t1_r0, "posts"."title" AS t1_r1, "posts"."created_at" AS t1_r2, "posts"."updated_at" AS t1_r3, "posts"."blog_id" AS t1_r4 FROM "blogs" LEFT OUTER JOIN "posts" ON "posts"."blog_id" = "blogs"."id" WHERE "blogs"."name" = ? AND "posts"."title" = ?  [["name", "Blog 1"], ["title", "Post 1-1"]]

    includes + references = eager_loading

  4. Joins brings association data using inner join.

     User.joins(:posts)
     # =>
     SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"

Intention for eager loading

# Give me users with polish addresses and preload only polish addresses
User.includes(:addresses).where("addresses.country = ?", "Poland")

# Give me users with polish addresses and preload only polish addresses(same, but inner join)
User.joins(:addresses).where("addresses.country = ?", "Poland").includes(:addresses)

# Give me users with polish addresses but preload all of their addresses.
User.joins(:addresses).where("addresses.country = ?", "Poland").preload(:addresses)

Too much query

Array

DB query

sort_by

order

.select { c c.label != 'All' }

.where.not(label: 'All')

http://gavinmiller.io/2013/getting-to-know-pluck-and-select/
http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html
http://blog.arkency.com/2013/12/rails4-preloading/
http://collectiveidea.com/blog/archives/2015/03/05/optimizing-rails-for-memory-usage-part-3-pluck-and-database-laziness