Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #10605 (closed defect: fixed)

Opened 5 months ago

Last modified 5 months ago

[PATCH] Dont use find in AR::Base#exists?

Reported by: fcheung Assigned to: core
Priority: normal Milestone: 2.x
Component: ActiveRecord Version: edge
Severity: normal Keywords: verified
Cc:

Description

AR::Base#exists? currently boils down to !find(:first, :select => 'id').nil? whereas it's not necessary to instantiate any ActiveRecord objects. Not doing this has 2 advantages as far as I'm concerned:

  • it's a little bit faster, since it's doing less work (I've verified this)
  • you don't have to worry in your after_find callbacks that you might get called with fewer attributes than normal

Attachments

dont_use_find_in_exists.diff (0.9 kB) - added by fcheung on 12/23/07 19:23:05.
without_sql_variable.diff (0.9 kB) - added by jamesh on 12/23/07 21:16:48.
Same as the original patch, but without the 'sql' variable.
using_select_value.diff (0.9 kB) - added by protocool on 12/23/07 21:47:00.
Again, same as original, bu also eliminates sql variable and uses select_value connection call
use_select_values.diff (0.9 kB) - added by fcheung on 12/23/07 22:39:11.

Change History

12/23/07 19:23:05 changed by fcheung

  • attachment dont_use_find_in_exists.diff added.

12/23/07 21:15:46 changed by jamesh

I'm definitely for this idea. As a suggestion, I've submitted your path without the use of the instance variable. This is largely a stylistic choice, but there's no real sense in creating a variable that only used once.

Either way, I've verified and give you my +1.

12/23/07 21:16:48 changed by jamesh

  • attachment without_sql_variable.diff added.

Same as the original patch, but without the 'sql' variable.

(follow-up: ↓ 3 ) 12/23/07 21:45:34 changed by protocool

I'm also a +1 on this - I can't replicate Josh's behaviour of find() being faster than going straight to the connection.

And... I'm also submitting an alternate patch - there's no point in doing select_all (which hashifies the resulting row) when select_value is pretty much exactly what you want.

12/23/07 21:47:00 changed by protocool

  • attachment using_select_value.diff added.

Again, same as original, bu also eliminates sql variable and uses select_value connection call

(in reply to: ↑ 2 ) 12/23/07 21:48:36 changed by jamesh

I'm going to specifically direct my +1 to protocool's patch. I think this one hits the nail on the head.

Replying to protocool:

I'm also a +1 on this - I can't replicate Josh's behaviour of find() being faster than going straight to the connection. And... I'm also submitting an alternate patch - there's no point in doing select_all (which hashifies the resulting row) when select_value is pretty much exactly what you want.

12/23/07 21:51:03 changed by fcheung

D'oh! Should have thought of that :-)

12/23/07 22:04:01 changed by hasmanyjosh

Don't pay too much mind to my claims about those measurements. It was a while ago, I don't remember exactly what I measured, and I can't find the data anymore.

#select_value calls #select_all, then extracts the value from the hash. It doesn't save you any work, but actually adds a tiny bit more effort.

(follow-up: ↓ 7 ) 12/23/07 22:20:32 changed by protocool

Josh is right... I stupidly assumed that select_value would delegate to select_values - but it does not.

IMHO it should... so rather than change the patch to be:

!select_values(construct_finder_sql(...)).empty? 

I would argue that select_value should be changed at some point in the not-to-distant future :-)

(in reply to: ↑ 6 ) 12/23/07 22:31:30 changed by jamesh

I've tried your recommendation, but found that there's a failure on the very first test for exists?. I.e. Object.exists?(1) fails (line 25, finder_test.rb).

Replying to protocool:

Josh is right... I stupidly assumed that select_value would delegate to select_values - but it does not. IMHO it should... so rather than change the patch to be: {{{ !select_values(construct_finder_sql(...)).empty? }}} I would argue that select_value should be changed at some point in the not-to-distant future :-)

12/23/07 22:39:11 changed by fcheung

  • attachment use_select_values.diff added.

(follow-up: ↓ 9 ) 12/23/07 22:56:22 changed by fcheung

Do we have some sort of consensus then ?

(in reply to: ↑ 8 ) 12/23/07 23:04:55 changed by jamesh

Replying to fcheung:

Do we have some sort of consensus then ?

In light of hasmanyjosh's response, I'd like to nominate my patch as the consensus. It's merely fcheung's patch without the variable. It's a little cleaner than his original submission without the introduced variable.

12/23/07 23:12:56 changed by fcheung

There's definitely a difference between select_all and select_values though, although I don't know enough to say which one is preferable (and I expect that it doesn't make any difference in this case)

12/24/07 07:39:37 changed by protocool

Fred,

(perhaps it's an oversight but) select_values is not query-cached, while select_all (and subsequently select_value) is.

Personally I prefer seeing something explicit like select_value but either that or select_all will be consistent with query caching behavior seen with the current exists? implementation.

12/24/07 11:18:21 changed by fcheung

In that case absolutely, jamesh's patch all the way! Now to find a missing +1 ...

12/24/07 12:31:43 changed by dbussink

+1 Seems reasonable to me

12/24/07 12:33:41 changed by fxn

+1

12/24/07 12:37:25 changed by fcheung

  • keywords set to verified.

01/02/08 21:39:57 changed by rick

  • status changed from new to closed.
  • resolution set to fixed.

(In [8531]) Optimize ActiveRecord::Base#exists? to use #select_all instead of #find. Closes #10605 [jamesh, fcheung, protocool]