Skip to content

Loading…

Changing AR:CollectionAssociation#empty? to use #exists? #7270

Merged
merged 1 commit into from

4 participants

@beerlington

COUNT(*) queries can be slow in PostgreSQL, #exists? avoids this by selecting a single record. @jonleighton suggested in issue #3179 that #empty? should be patched to use #exists? for the same benefit. I couldn't think of a great way to test it since the external behavior is not changing. If anyone has any suggestions for tests though, I would be more than happy to add them.

@beerlington beerlington Changing AR:CollectionAssociation#empty? to use #exists?
COUNT(*) queries can be slow in PostgreSQL, #exists? avoids this by
selecting a single record.
d1f7590
@rafaelfranca
Ruby on Rails member

You can test asserting the generated SQL.

@jonleighton
Ruby on Rails member

The problem with asserting the SQL is that it's fragile. I think this is fine as it is, given it's just a perf optimisation.

@jonleighton jonleighton merged commit 6126f02 into rails:master
@carlosantoniodasilva
Ruby on Rails member

@jonleighton since empty? was already patched to make use of exists?, I still think we could add present? (and maybe blank?) to the collection association handling as well, to avoid method_missing, wdyt? I can do the changes later if necessary. Thanks.

@jonleighton
Ruby on Rails member
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 5, 2012
  1. @beerlington

    Changing AR:CollectionAssociation#empty? to use #exists?

    beerlington committed
    COUNT(*) queries can be slow in PostgreSQL, #exists? avoids this by
    selecting a single record.
This page is out of date. Refresh to see the latest.
Showing with 11 additions and 3 deletions.
  1. +11 −3 activerecord/lib/active_record/associations/collection_association.rb
View
14 activerecord/lib/active_record/associations/collection_association.rb
@@ -270,12 +270,20 @@ def length
load_target.size
end
- # Returns true if the collection is empty. Equivalent to
- # <tt>collection.size.zero?</tt>. If the collection has not been already
+ # Returns true if the collection is empty.
+ #
+ # If the collection has been loaded or the <tt>:counter_sql</tt> option
+ # is provided, it is equivalent to <tt>collection.size.zero?</tt>. If the
+ # collection has not been loaded, it is equivalent to
+ # <tt>collection.exists?</tt>. If the collection has not already been
# loaded and you are going to fetch the records anyway it is better to
# check <tt>collection.length.zero?</tt>.
def empty?
- size.zero?
+ if loaded? || options[:counter_sql]
+ size.zero?
+ else
+ !scope.exists?
+ end
end
# Returns true if the collections is not empty.
Something went wrong with that request. Please try again.