SlideShare a Scribd company logo
1 of 35
Download to read offline
Ror lab. season 2
     - the 11th round -


   Active Record
Query Interface (2)

     December 1st, 2012

       Hyoseong Choi
Eager Loading
     Associations
          : as few queries as possible

N + 1 queries problem


 clients = Client.limit(10)
  
 clients.each do |client|
   puts client.address.postcode
 end
Eager Loading
     Associations
          : as few queries as possible

Solution to N + 1 queries problem         Only 2 queries

 clients = Client.includes(:address).limit(10)
  
 clients.each do |client|
   puts client.address.postcode
 end


SELECT * FROM clients LIMIT 10
SELECT addresses.* FROM addresses
  WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))
Eager Loading
      Associations
- Eager Loading Multiple Associations -
 Array of Multiple Associations


 Post.includes(:category, :comments)



 Nested Associations Hash


 Category.includes(
   :posts => [{:comments => :guest}, :tags]).find(1)
Eager Loading
       Associations
- Conditions on Eager Loaded Associations -

 conditional “joins” > conditional “includes”


   Post.includes(:comments)
       .where("comments.visible", true)



  SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5
  FROM "posts"
  LEFT OUTER JOIN "comments"
  ON "comments"."post_id" = "posts"."id"
  WHERE (comments.visible = 1)
Eager Loading
       Associations
- Conditions on Eager Loaded Associations -
                  INNER JOIN                      LEFT OUTER JOIN
 conditional “joins” > conditional “includes”


   Post.includes(:comments)
       .where("comments.visible", true)



  SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5
  FROM "posts"
  LEFT OUTER JOIN "comments"
  ON "comments"."post_id" = "posts"."id"
  WHERE (comments.visible = 1)
Scopes

• ToSQL AST(Abstract Syntax Tree) manger for Ruby
  :a
     specify ARel queries

• Referenced as method calls on the
  association objects or model
• finder methods in a scope
• return an ActiveRecord::Relation object
Scopes

class Post < ActiveRecord::Base
  scope :published, where(:published => true)
end
                        ARel query
Scopes
chainable
class Post < ActiveRecord::Base
  scope :published,
  where(:published => true).joins(:category)
end




chainable within scopes
class Post < ActiveRecord::Base
  scope :published, where(:published => true)
  scope :published_and_commented,
published.and(self.arel_table[:comments_count].gt(0))
end
Scopes
             To call the scope

Post.published # => [published posts]

category = Category.first
category.posts.published
# => [published posts belonging to this category]
Scopes
               Working with times

class Post < ActiveRecord::Base
  scope :last_week,
  lambda { where("created_at < ?", Time.zone.now ) }
end
     a lambda so that the scope is evaluated every time
Scopes
          Passing in arguments
class Post < ActiveRecord::Base
  scope :1_week_before,
  lambda { |time| where("created_at < ?", time) }
end

Post.1_week_before(Time.zone.now)




class Post < ActiveRecord::Base
  def self.1_week_before(time)
    where("created_at < ?", time)
  end
end              ***What about “as   a class method” ?
Scopes
                          Passing in arguments
            class Post < ActiveRecord::Base
              scope :1_week_before,
              lambda { |time| where("created_at < ?", time) }
            end

            Post.1_week_before(Time.zone.now)


                   b le
            r ea
     e fe   class Post < ActiveRecord::Base
pr            def self.1_week_before(time)
                where("created_at < ?", time)
              end
            end              ***What about “as   a class method” ?
Scopes
          Passing in arguments


category.posts.1_week_before(time)
Scopes
          Working with Scopes


client = Client.find_by_first_name("Ryan")
orders = client.orders.scoped




orders.where("created_at > ?", 30.days.ago)
Scopes
        Applying a default scope


class Client < ActiveRecord::Base
  default_scope where("removed_at IS NULL")
end



SELECT * FROM clients WHERE removed_at IS NULL
Scopes
          Removing all scopes


Client.unscoped.all




             Especially useful,
      when escaping the default_scope
Dynamic Finders
• Model.find_by_attribute_name
• Model.find_all_by_attribute_name
• Model.find_last_by_attribute_name
• Model.find_by_attribute_name!
• Model.find_by_attr1_and_attr2
Rails 3.2 => Argument Error on missing fields
Find or build
      a new object

• first_or_create
• first_or_create!      Exception on invalid

• first_or_initialize
Find or build
          a new object
• first_or_create
 Client.where(:first_name =>
 'Andy').first_or_create(:locked => false)
 # => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: false,
 created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">


 Client.find_or_create_by_first_name(:first_name =>
 "Andy", :locked => false)


SELECT * FROM clients WHERE (clients.first_name = 'Andy') LIMIT 1
BEGIN
INSERT INTO clients (created_at, first_name, locked, orders_count, updated_at)
VALUES ('2011-08-30 05:22:57', 'Andy', 0, NULL, '2011-08-30 05:22:57')
COMMIT
Find or build
        a new object
• first_or_create!
 class Client < ActiveRecord::Base
   validates :orders_count, :presence => true
 end

 Client.where(:first_name => 'Andy').first_or_create!
 (:locked => false)
 # => ActiveRecord::RecordInvalid: Validation failed: Orders
 count can't be blank
Find or build
         a new object
• first_or_initialize
 nick = Client.where(:first_name =>
 'Nick').first_or_initialize(:locked => false)
 # => <Client id: nil, first_name: "Nick", orders_count: 0,
 locked: false, created_at: "2011-08-30 06:09:27", updated_at:
 "2011-08-30 06:09:27">
  
 SELECT * FROM clients WHERE (clients.first_name = 'Nick') LIMIT 1

 nick.persisted?
 # => false
 nick.new_record?
 # => true
 nick.save
 # => true


persisted? vs new_record?
Finding by SQL
 : return an array of objects
 where each object indicates a record

Client.find_by_sql("SELECT * FROM clients
  INNER JOIN orders ON clients.id = orders.client_id
  ORDER clients.created_at desc")



cf. connection.select_all
       an array of hash
select_all
 : return an array of hash
 where each hash indicates a record

Client.connection.select_all("SELECT * FROM clients
WHERE id = '1'")




cf. find_by_sql => instantiates objects
pluck
To query a single column from the underlying table of a model
To return an array of values


Client.where(:active => true).pluck(:id)
# SELECT id FROM clients WHERE active = 1
 
Client.uniq.pluck(:role)
# SELECT DISTINCT role FROM clients




Client.select(:id).map { |c| c.id }

    Client.pluck(:id)
Existence of
        Objects
Client.exists?(1)

Client.exists?(1,2,3)
# or
Client.exists?([1,2,3])

Client.where(:first_name => 'Ryan').exists?

Client.exists?



cf. find method
Existence of
        Objects
# via a model
Post.any?
Post.many?
 
# via a named scope
Post.recent.any?
Post.recent.many?
 
# via a relation
Post.where(:published => true).any?
Post.where(:published => true).many?
 
# via an association
Post.first.categories.any?
Post.first.categories.many?
Calculations
 Client.count
 # SELECT count(*) AS count_all FROM clients

 Client.where(:first_name => 'Ryan').count
 # SELECT count(*) AS count_all FROM clients WHERE
 (first_name = 'Ryan')

 Client.includes("orders").where(:first_name =>
 'Ryan', :orders => {:status => 'received'}).count



SELECT count(DISTINCT clients.id) AS count_all FROM clients
  LEFT OUTER JOIN orders ON orders.client_id = client.id WHERE
  (clients.first_name = 'Ryan' AND orders.status = 'received')
Calculations
Client.count(:age)

Client.average("orders_count")

Client.minimum("age")

Client.maximum("age")

Client.sum("orders_count")
Running EXPLAIN
            a pretty printing that emulates the one of the database shells



            User.where(:id => 1).joins(:posts).explain




EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id`
WHERE `users`.`id` = 1
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const |    1 |             |
|  1 | SIMPLE      | posts | ALL   | NULL          | NULL    | NULL    | NULL  |    1 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
2 rows in set (0.00 sec)



under MySQL
Running EXPLAIN
            a pretty printing that emulates the one of the database shells



            User.where(:id => 1).joins(:posts).explain




EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
WHERE "users"."id" = 1
                                  QUERY PLAN
------------------------------------------------------------------------------
 Nested Loop Left Join  (cost=0.00..37.24 rows=8 width=0)
   Join Filter: (posts.user_id = users.id)
   ->  Index Scan using users_pkey on users  (cost=0.00..8.27 rows=1 width=4)
         Index Cond: (id = 1)
   ->  Seq Scan on posts  (cost=0.00..28.88 rows=8 width=4)
         Filter: (posts.user_id = 1)
(6 rows)


under PostgreSQL
Running EXPLAIN
                                       Eager Loading


          User.where(:id => 1).includes(:posts).explain


 EXPLAIN for: SELECT `users`.* FROM `users`  WHERE `users`.`id` = 1
 +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
 | id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
 +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
 |  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
 +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
 1 row in set (0.00 sec)
  
 EXPLAIN for: SELECT `posts`.* FROM `posts`  WHERE `posts`.`user_id` IN (1)
 +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
 | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
 +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
 |  1 | SIMPLE      | posts | ALL  | NULL          | NULL | NULL    | NULL |    1 | Using where |
 +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
 1 row in set (0.00 sec)



under MySQL
Running EXPLAIN
            Automatic EXPLAIN

To set the threshold in seconds
config.active_record.auto_explain_threshold_in_seconds



• disables automatic EXPLAIN => nil or no AR logger
• Development mode => default, 0.5 sec
• Test mode => nil
• Production mode => nil
Running EXPLAIN
     Disabling Automatic EXPLAIN

To be selectively silenced with
 ActiveRecord::Base.silence_auto_explain do
   # no automatic EXPLAIN is triggered here
 end



• useful for queries are slow but fine
  : a heavyweight report of a admin interface
감사합니다.

More Related Content

What's hot

Scala ActiveRecord
Scala ActiveRecordScala ActiveRecord
Scala ActiveRecord
scalaconfjp
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Thomas Fuchs
 

What's hot (20)

Scala ActiveRecord
Scala ActiveRecordScala ActiveRecord
Scala ActiveRecord
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
 
descriptive programming
descriptive programmingdescriptive programming
descriptive programming
 
Alternate JVM Languages
Alternate JVM LanguagesAlternate JVM Languages
Alternate JVM Languages
 
Python: Basic Inheritance
Python: Basic InheritancePython: Basic Inheritance
Python: Basic Inheritance
 
Nativescript angular
Nativescript angularNativescript angular
Nativescript angular
 
Clean up your code with C#6
Clean up your code with C#6Clean up your code with C#6
Clean up your code with C#6
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6
 
Object Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypassObject Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypass
 
Python and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super ToolsPython and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super Tools
 
Load Data Fast!
Load Data Fast!Load Data Fast!
Load Data Fast!
 
JavaFX 2.0 With Alternative Languages - JavaOne 2011
JavaFX 2.0 With Alternative Languages - JavaOne 2011JavaFX 2.0 With Alternative Languages - JavaOne 2011
JavaFX 2.0 With Alternative Languages - JavaOne 2011
 
The Ring programming language version 1.5.4 book - Part 38 of 185
The Ring programming language version 1.5.4 book - Part 38 of 185The Ring programming language version 1.5.4 book - Part 38 of 185
The Ring programming language version 1.5.4 book - Part 38 of 185
 
Activator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetupActivator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetup
 
The Ring programming language version 1.2 book - Part 27 of 84
The Ring programming language version 1.2 book - Part 27 of 84The Ring programming language version 1.2 book - Part 27 of 84
The Ring programming language version 1.2 book - Part 27 of 84
 
RIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTRIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWT
 
Slick: Bringing Scala’s Powerful Features to Your Database Access
Slick: Bringing Scala’s Powerful Features to Your Database Access Slick: Bringing Scala’s Powerful Features to Your Database Access
Slick: Bringing Scala’s Powerful Features to Your Database Access
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
 
Building an api using golang and postgre sql v1.0
Building an api using golang and postgre sql v1.0Building an api using golang and postgre sql v1.0
Building an api using golang and postgre sql v1.0
 

Similar to ActiveRecord Query Interface (2), Season 2

Active Record Query Interface (2), Season 1
Active Record Query Interface (2), Season 1Active Record Query Interface (2), Season 1
Active Record Query Interface (2), Season 1
RORLAB
 
Active Record Query Interface (1), Season 2
Active Record Query Interface (1), Season 2Active Record Query Interface (1), Season 2
Active Record Query Interface (1), Season 2
RORLAB
 
Антипаттерны модульного тестирования
Антипаттерны модульного тестированияАнтипаттерны модульного тестирования
Антипаттерны модульного тестирования
MitinPavel
 
Taxonomy of Scala
Taxonomy of ScalaTaxonomy of Scala
Taxonomy of Scala
shinolajla
 
Кирилл Безпалый, .NET Developer, Ciklum
Кирилл Безпалый, .NET Developer, CiklumКирилл Безпалый, .NET Developer, Ciklum
Кирилл Безпалый, .NET Developer, Ciklum
Alina Vilk
 
YiiConf 2012 - Alexander Makarov - Yii2, what's new
YiiConf 2012 - Alexander Makarov - Yii2, what's newYiiConf 2012 - Alexander Makarov - Yii2, what's new
YiiConf 2012 - Alexander Makarov - Yii2, what's new
Alexander Makarov
 

Similar to ActiveRecord Query Interface (2), Season 2 (20)

Active Record Query Interface (2), Season 1
Active Record Query Interface (2), Season 1Active Record Query Interface (2), Season 1
Active Record Query Interface (2), Season 1
 
Active Record Query Interface (1), Season 2
Active Record Query Interface (1), Season 2Active Record Query Interface (1), Season 2
Active Record Query Interface (1), Season 2
 
科特林λ學
科特林λ學科特林λ學
科特林λ學
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Timothy N. Tsvetkov, Rails 3.1
Timothy N. Tsvetkov, Rails 3.1Timothy N. Tsvetkov, Rails 3.1
Timothy N. Tsvetkov, Rails 3.1
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
 
Intro to Rails 4
Intro to Rails 4Intro to Rails 4
Intro to Rails 4
 
Антипаттерны модульного тестирования
Антипаттерны модульного тестированияАнтипаттерны модульного тестирования
Антипаттерны модульного тестирования
 
Taxonomy of Scala
Taxonomy of ScalaTaxonomy of Scala
Taxonomy of Scala
 
Кирилл Безпалый, .NET Developer, Ciklum
Кирилл Безпалый, .NET Developer, CiklumКирилл Безпалый, .NET Developer, Ciklum
Кирилл Безпалый, .NET Developer, Ciklum
 
Why ruby
Why rubyWhy ruby
Why ruby
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails
 
Rails 3 (beta) Roundup
Rails 3 (beta) RoundupRails 3 (beta) Roundup
Rails 3 (beta) Roundup
 
The Ring programming language version 1.5.2 book - Part 37 of 181
The Ring programming language version 1.5.2 book - Part 37 of 181The Ring programming language version 1.5.2 book - Part 37 of 181
The Ring programming language version 1.5.2 book - Part 37 of 181
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
 
YiiConf 2012 - Alexander Makarov - Yii2, what's new
YiiConf 2012 - Alexander Makarov - Yii2, what's newYiiConf 2012 - Alexander Makarov - Yii2, what's new
YiiConf 2012 - Alexander Makarov - Yii2, what's new
 
KSP intro
KSP introKSP intro
KSP intro
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme Swift
 
Rails Concurrency Gotchas
Rails Concurrency GotchasRails Concurrency Gotchas
Rails Concurrency Gotchas
 
CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29
 

More from RORLAB

Active Support Core Extension (3)
Active Support Core Extension (3)Active Support Core Extension (3)
Active Support Core Extension (3)
RORLAB
 
Active Support Core Extension (2)
Active Support Core Extension (2)Active Support Core Extension (2)
Active Support Core Extension (2)
RORLAB
 
Action Controller Overview, Season 2
Action Controller Overview, Season 2Action Controller Overview, Season 2
Action Controller Overview, Season 2
RORLAB
 
Action View Form Helpers - 2, Season 2
Action View Form Helpers - 2, Season 2Action View Form Helpers - 2, Season 2
Action View Form Helpers - 2, Season 2
RORLAB
 
Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2
RORLAB
 
Layouts and Rendering in Rails, Season 2
Layouts and Rendering in Rails, Season 2Layouts and Rendering in Rails, Season 2
Layouts and Rendering in Rails, Season 2
RORLAB
 

More from RORLAB (20)

Getting Started with Rails (4)
Getting Started with Rails (4) Getting Started with Rails (4)
Getting Started with Rails (4)
 
Getting Started with Rails (3)
Getting Started with Rails (3) Getting Started with Rails (3)
Getting Started with Rails (3)
 
Getting Started with Rails (2)
Getting Started with Rails (2)Getting Started with Rails (2)
Getting Started with Rails (2)
 
Getting Started with Rails (1)
Getting Started with Rails (1)Getting Started with Rails (1)
Getting Started with Rails (1)
 
Self join in active record association
Self join in active record associationSelf join in active record association
Self join in active record association
 
Asset Pipeline in Ruby on Rails
Asset Pipeline in Ruby on RailsAsset Pipeline in Ruby on Rails
Asset Pipeline in Ruby on Rails
 
레일스가이드 한글번역 공개프로젝트 RORLabGuides 소개
레일스가이드 한글번역 공개프로젝트 RORLabGuides 소개레일스가이드 한글번역 공개프로젝트 RORLabGuides 소개
레일스가이드 한글번역 공개프로젝트 RORLabGuides 소개
 
Active Support Core Extension (3)
Active Support Core Extension (3)Active Support Core Extension (3)
Active Support Core Extension (3)
 
Active Support Core Extension (2)
Active Support Core Extension (2)Active Support Core Extension (2)
Active Support Core Extension (2)
 
Active Support Core Extensions (1)
Active Support Core Extensions (1)Active Support Core Extensions (1)
Active Support Core Extensions (1)
 
Action Controller Overview, Season 2
Action Controller Overview, Season 2Action Controller Overview, Season 2
Action Controller Overview, Season 2
 
Action View Form Helpers - 2, Season 2
Action View Form Helpers - 2, Season 2Action View Form Helpers - 2, Season 2
Action View Form Helpers - 2, Season 2
 
Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2
 
Layouts and Rendering in Rails, Season 2
Layouts and Rendering in Rails, Season 2Layouts and Rendering in Rails, Season 2
Layouts and Rendering in Rails, Season 2
 
Active Record Association (2), Season 2
Active Record Association (2), Season 2Active Record Association (2), Season 2
Active Record Association (2), Season 2
 
ActiveRecord Association (1), Season 2
ActiveRecord Association (1), Season 2ActiveRecord Association (1), Season 2
ActiveRecord Association (1), Season 2
 
ActiveRecord Callbacks & Observers, Season 2
ActiveRecord Callbacks & Observers, Season 2ActiveRecord Callbacks & Observers, Season 2
ActiveRecord Callbacks & Observers, Season 2
 
ActiveRecord Validations, Season 2
ActiveRecord Validations, Season 2ActiveRecord Validations, Season 2
ActiveRecord Validations, Season 2
 
Rails Database Migration, Season 2
Rails Database Migration, Season 2Rails Database Migration, Season 2
Rails Database Migration, Season 2
 
Getting started with Rails (4), Season 2
Getting started with Rails (4), Season 2Getting started with Rails (4), Season 2
Getting started with Rails (4), Season 2
 

Recently uploaded

Spellings Wk 3 English CAPS CARES Please Practise
Spellings Wk 3 English CAPS CARES Please PractiseSpellings Wk 3 English CAPS CARES Please Practise
Spellings Wk 3 English CAPS CARES Please Practise
AnaAcapella
 
The basics of sentences session 3pptx.pptx
The basics of sentences session 3pptx.pptxThe basics of sentences session 3pptx.pptx
The basics of sentences session 3pptx.pptx
heathfieldcps1
 

Recently uploaded (20)

Python Notes for mca i year students osmania university.docx
Python Notes for mca i year students osmania university.docxPython Notes for mca i year students osmania university.docx
Python Notes for mca i year students osmania university.docx
 
Jamworks pilot and AI at Jisc (20/03/2024)
Jamworks pilot and AI at Jisc (20/03/2024)Jamworks pilot and AI at Jisc (20/03/2024)
Jamworks pilot and AI at Jisc (20/03/2024)
 
Single or Multiple melodic lines structure
Single or Multiple melodic lines structureSingle or Multiple melodic lines structure
Single or Multiple melodic lines structure
 
Accessible Digital Futures project (20/03/2024)
Accessible Digital Futures project (20/03/2024)Accessible Digital Futures project (20/03/2024)
Accessible Digital Futures project (20/03/2024)
 
Spellings Wk 3 English CAPS CARES Please Practise
Spellings Wk 3 English CAPS CARES Please PractiseSpellings Wk 3 English CAPS CARES Please Practise
Spellings Wk 3 English CAPS CARES Please Practise
 
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptx
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptxHMCS Max Bernays Pre-Deployment Brief (May 2024).pptx
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptx
 
How to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POSHow to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POS
 
REMIFENTANIL: An Ultra short acting opioid.pptx
REMIFENTANIL: An Ultra short acting opioid.pptxREMIFENTANIL: An Ultra short acting opioid.pptx
REMIFENTANIL: An Ultra short acting opioid.pptx
 
FSB Advising Checklist - Orientation 2024
FSB Advising Checklist - Orientation 2024FSB Advising Checklist - Orientation 2024
FSB Advising Checklist - Orientation 2024
 
The basics of sentences session 3pptx.pptx
The basics of sentences session 3pptx.pptxThe basics of sentences session 3pptx.pptx
The basics of sentences session 3pptx.pptx
 
How to Give a Domain for a Field in Odoo 17
How to Give a Domain for a Field in Odoo 17How to Give a Domain for a Field in Odoo 17
How to Give a Domain for a Field in Odoo 17
 
Sociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning ExhibitSociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning Exhibit
 
Application orientated numerical on hev.ppt
Application orientated numerical on hev.pptApplication orientated numerical on hev.ppt
Application orientated numerical on hev.ppt
 
Fostering Friendships - Enhancing Social Bonds in the Classroom
Fostering Friendships - Enhancing Social Bonds  in the ClassroomFostering Friendships - Enhancing Social Bonds  in the Classroom
Fostering Friendships - Enhancing Social Bonds in the Classroom
 
Food safety_Challenges food safety laboratories_.pdf
Food safety_Challenges food safety laboratories_.pdfFood safety_Challenges food safety laboratories_.pdf
Food safety_Challenges food safety laboratories_.pdf
 
Graduate Outcomes Presentation Slides - English
Graduate Outcomes Presentation Slides - EnglishGraduate Outcomes Presentation Slides - English
Graduate Outcomes Presentation Slides - English
 
Towards a code of practice for AI in AT.pptx
Towards a code of practice for AI in AT.pptxTowards a code of practice for AI in AT.pptx
Towards a code of practice for AI in AT.pptx
 
Micro-Scholarship, What it is, How can it help me.pdf
Micro-Scholarship, What it is, How can it help me.pdfMicro-Scholarship, What it is, How can it help me.pdf
Micro-Scholarship, What it is, How can it help me.pdf
 
ICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptx
 
General Principles of Intellectual Property: Concepts of Intellectual Proper...
General Principles of Intellectual Property: Concepts of Intellectual  Proper...General Principles of Intellectual Property: Concepts of Intellectual  Proper...
General Principles of Intellectual Property: Concepts of Intellectual Proper...
 

ActiveRecord Query Interface (2), Season 2

  • 1. Ror lab. season 2 - the 11th round - Active Record Query Interface (2) December 1st, 2012 Hyoseong Choi
  • 2. Eager Loading Associations : as few queries as possible N + 1 queries problem clients = Client.limit(10)   clients.each do |client|   puts client.address.postcode end
  • 3. Eager Loading Associations : as few queries as possible Solution to N + 1 queries problem Only 2 queries clients = Client.includes(:address).limit(10)   clients.each do |client|   puts client.address.postcode end SELECT * FROM clients LIMIT 10 SELECT addresses.* FROM addresses   WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))
  • 4. Eager Loading Associations - Eager Loading Multiple Associations - Array of Multiple Associations Post.includes(:category, :comments) Nested Associations Hash Category.includes( :posts => [{:comments => :guest}, :tags]).find(1)
  • 5. Eager Loading Associations - Conditions on Eager Loaded Associations - conditional “joins” > conditional “includes” Post.includes(:comments) .where("comments.visible", true) SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE (comments.visible = 1)
  • 6. Eager Loading Associations - Conditions on Eager Loaded Associations - INNER JOIN LEFT OUTER JOIN conditional “joins” > conditional “includes” Post.includes(:comments) .where("comments.visible", true) SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE (comments.visible = 1)
  • 7. Scopes • ToSQL AST(Abstract Syntax Tree) manger for Ruby :a specify ARel queries • Referenced as method calls on the association objects or model • finder methods in a scope • return an ActiveRecord::Relation object
  • 8. Scopes class Post < ActiveRecord::Base   scope :published, where(:published => true) end ARel query
  • 9. Scopes chainable class Post < ActiveRecord::Base   scope :published, where(:published => true).joins(:category) end chainable within scopes class Post < ActiveRecord::Base   scope :published, where(:published => true)   scope :published_and_commented, published.and(self.arel_table[:comments_count].gt(0)) end
  • 10. Scopes To call the scope Post.published # => [published posts] category = Category.first category.posts.published # => [published posts belonging to this category]
  • 11. Scopes Working with times class Post < ActiveRecord::Base   scope :last_week, lambda { where("created_at < ?", Time.zone.now ) } end a lambda so that the scope is evaluated every time
  • 12. Scopes Passing in arguments class Post < ActiveRecord::Base   scope :1_week_before, lambda { |time| where("created_at < ?", time) } end Post.1_week_before(Time.zone.now) class Post < ActiveRecord::Base   def self.1_week_before(time)     where("created_at < ?", time)   end end ***What about “as a class method” ?
  • 13. Scopes Passing in arguments class Post < ActiveRecord::Base   scope :1_week_before, lambda { |time| where("created_at < ?", time) } end Post.1_week_before(Time.zone.now) b le r ea e fe class Post < ActiveRecord::Base pr   def self.1_week_before(time)     where("created_at < ?", time)   end end ***What about “as a class method” ?
  • 14. Scopes Passing in arguments category.posts.1_week_before(time)
  • 15. Scopes Working with Scopes client = Client.find_by_first_name("Ryan") orders = client.orders.scoped orders.where("created_at > ?", 30.days.ago)
  • 16. Scopes Applying a default scope class Client < ActiveRecord::Base   default_scope where("removed_at IS NULL") end SELECT * FROM clients WHERE removed_at IS NULL
  • 17. Scopes Removing all scopes Client.unscoped.all Especially useful, when escaping the default_scope
  • 18. Dynamic Finders • Model.find_by_attribute_name • Model.find_all_by_attribute_name • Model.find_last_by_attribute_name • Model.find_by_attribute_name! • Model.find_by_attr1_and_attr2 Rails 3.2 => Argument Error on missing fields
  • 19. Find or build a new object • first_or_create • first_or_create! Exception on invalid • first_or_initialize
  • 20. Find or build a new object • first_or_create Client.where(:first_name => 'Andy').first_or_create(:locked => false) # => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27"> Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false) SELECT * FROM clients WHERE (clients.first_name = 'Andy') LIMIT 1 BEGIN INSERT INTO clients (created_at, first_name, locked, orders_count, updated_at) VALUES ('2011-08-30 05:22:57', 'Andy', 0, NULL, '2011-08-30 05:22:57') COMMIT
  • 21. Find or build a new object • first_or_create! class Client < ActiveRecord::Base validates :orders_count, :presence => true end Client.where(:first_name => 'Andy').first_or_create! (:locked => false) # => ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
  • 22. Find or build a new object • first_or_initialize nick = Client.where(:first_name => 'Nick').first_or_initialize(:locked => false) # => <Client id: nil, first_name: "Nick", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">   SELECT * FROM clients WHERE (clients.first_name = 'Nick') LIMIT 1 nick.persisted? # => false nick.new_record? # => true nick.save # => true persisted? vs new_record?
  • 23. Finding by SQL : return an array of objects where each object indicates a record Client.find_by_sql("SELECT * FROM clients   INNER JOIN orders ON clients.id = orders.client_id   ORDER clients.created_at desc") cf. connection.select_all an array of hash
  • 24. select_all : return an array of hash where each hash indicates a record Client.connection.select_all("SELECT * FROM clients WHERE id = '1'") cf. find_by_sql => instantiates objects
  • 25. pluck To query a single column from the underlying table of a model To return an array of values Client.where(:active => true).pluck(:id) # SELECT id FROM clients WHERE active = 1   Client.uniq.pluck(:role) # SELECT DISTINCT role FROM clients Client.select(:id).map { |c| c.id } Client.pluck(:id)
  • 26. Existence of Objects Client.exists?(1) Client.exists?(1,2,3) # or Client.exists?([1,2,3]) Client.where(:first_name => 'Ryan').exists? Client.exists? cf. find method
  • 27. Existence of Objects # via a model Post.any? Post.many?   # via a named scope Post.recent.any? Post.recent.many?   # via a relation Post.where(:published => true).any? Post.where(:published => true).many?   # via an association Post.first.categories.any? Post.first.categories.many?
  • 28. Calculations Client.count # SELECT count(*) AS count_all FROM clients Client.where(:first_name => 'Ryan').count # SELECT count(*) AS count_all FROM clients WHERE (first_name = 'Ryan') Client.includes("orders").where(:first_name => 'Ryan', :orders => {:status => 'received'}).count SELECT count(DISTINCT clients.id) AS count_all FROM clients   LEFT OUTER JOIN orders ON orders.client_id = client.id WHERE   (clients.first_name = 'Ryan' AND orders.status = 'received')
  • 30. Running EXPLAIN a pretty printing that emulates the one of the database shells User.where(:id => 1).joins(:posts).explain EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ |  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const |    1 |             | |  1 | SIMPLE      | posts | ALL   | NULL          | NULL    | NULL    | NULL  |    1 | Using where | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ 2 rows in set (0.00 sec) under MySQL
  • 31. Running EXPLAIN a pretty printing that emulates the one of the database shells User.where(:id => 1).joins(:posts).explain EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "users"."id" = 1                                   QUERY PLAN ------------------------------------------------------------------------------  Nested Loop Left Join  (cost=0.00..37.24 rows=8 width=0)    Join Filter: (posts.user_id = users.id)    ->  Index Scan using users_pkey on users  (cost=0.00..8.27 rows=1 width=4)          Index Cond: (id = 1)    ->  Seq Scan on posts  (cost=0.00..28.88 rows=8 width=4)          Filter: (posts.user_id = 1) (6 rows) under PostgreSQL
  • 32. Running EXPLAIN Eager Loading User.where(:id => 1).includes(:posts).explain EXPLAIN for: SELECT `users`.* FROM `users`  WHERE `users`.`id` = 1 +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ |  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const |    1 |       | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ 1 row in set (0.00 sec)   EXPLAIN for: SELECT `posts`.* FROM `posts`  WHERE `posts`.`user_id` IN (1) +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ |  1 | SIMPLE      | posts | ALL  | NULL          | NULL | NULL    | NULL |    1 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) under MySQL
  • 33. Running EXPLAIN Automatic EXPLAIN To set the threshold in seconds config.active_record.auto_explain_threshold_in_seconds • disables automatic EXPLAIN => nil or no AR logger • Development mode => default, 0.5 sec • Test mode => nil • Production mode => nil
  • 34. Running EXPLAIN Disabling Automatic EXPLAIN To be selectively silenced with ActiveRecord::Base.silence_auto_explain do   # no automatic EXPLAIN is triggered here end • useful for queries are slow but fine : a heavyweight report of a admin interface
  • 36.