Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

has_one generates an ORDER BY clause in Rails 4 that may cause performance issues #12623

unspongeful opened this issue Oct 24, 2013 · 5 comments


Copy link

@unspongeful unspongeful commented Oct 24, 2013

I'm not sure if this is an intended change from Rails 3.2, as it doesn't appear in the CHANGELOG, but I'm seeing a performance regression with Rails 4 on large tables using Postgresql because of the added 'ORDER BY' clause.

Example code:

require 'bundler'

require 'active_record'

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')

ActiveRecord::Schema.define do
  create_table :users
  create_table :profiles do |t|
    t.integer :user_id

class User < ActiveRecord::Base
  has_one :profile
class Profile < ActiveRecord::Base
  belongs_to :user


user = User.first

queries = []
subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |name, s, f, id, values|
  queries << values[:sql]


puts queries.first

I get:

-- Rails 4.0.0 and 4.0.0rc3
SELECT  "profiles".* FROM "profiles"  WHERE "profiles"."user_id" = ?  ORDER BY "profiles"."id" ASC LIMIT 1

-- Rails 3.2.15
SELECT  "profiles".* FROM "profiles"  WHERE "profiles"."user_id" = 1 LIMIT 1

To return to pre-4.0 behaviour I've changed has_one to the following:

class User < ActiveRecord::Base
  has_one :profile, -> { order(nil) }
Copy link

@al2o3cr al2o3cr commented Oct 24, 2013

Peculiar that ordering on an indexed field would cause a performance hit; can you try running EXPLAIN against the 4.0.0 query vs. the 3.2.15 one in your DB to see what's changed?

Copy link

@rafaelfranca rafaelfranca commented Oct 24, 2013

This is intentional but it is not related to has_one but with the frist method.

You can find in the CHANGELOG entry:

Added default order to `first` to assure consistent results among different database engines. Introduced `take` as a replacement to the old behavior of first.
Copy link

@MSch MSch commented Jan 21, 2014

@rafaelfranca just ran into this. I read through #5153 and I can see the reasoning for .first but not why it should apply to has_one?

Copy link

@rafaelfranca rafaelfranca commented Jan 21, 2014

I think I misunderstood the issue. I'll reopen

@rafaelfranca rafaelfranca reopened this Jan 21, 2014
@ghost ghost assigned rafaelfranca Jan 21, 2014
rafaelfranca added a commit that referenced this issue Jan 21, 2014
…s anymore.

Since Rails 4.0, we add an ORDER BY in the `first` method to ensure consistent
results among different database engines. But for singular associations this
behavior is not needed since we will have one record to return. As this
ORDER BY option can lead some performance issues we are removing it for singular
associations accessors.

Fixes #12623.

Copy link

@MSch MSch commented Jan 21, 2014

@rafaelfranca THANKS THANKS THANKS!!!!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.