Rails 3中的MySql快速使用User.first而使用User.first(1)速度慢 - 为什么?

时间:2013-01-23 05:59:01

标签: mysql ruby-on-rails ruby-on-rails-3 rails-activerecord

我有一张桌子,里面有大约500,000名用户。当我使用我的Rails 3.0控制台并键入

User.first

我立刻得到了结果。但是当我输入

User.first(1)

需要几秒钟。可能导致这种情况的原因是什么?

注意:

之间发生了同样的事情
User.last

User.last(1)

1 个答案:

答案 0 :(得分:4)

我打开了Erb(Rails 3.0.7)中的日志显示并产生了以下

1.8.7 :004 > User.first
  User Load (4.3ms)  SELECT `users`.* FROM `users` LIMIT 1
 => #<User id: 1, email: "user@project.ru">
1.8.7 :005 > User.first(1)
  User Load (0.4ms)  SELECT `users`.* FROM `users`
 => #<User id: 1, email: "user@project.ru">
1.8.7 :008 > User.first(2)
  User Load (0.4ms)  SELECT `users`.* FROM `users`
 => [#<User id: 1, email: "user@project.ru", #<User id: 2, email: "user@gmail.com">]

因此,我们可以看到,当您在没有参数的情况下调用first时,它会按预期工作,但是当我们使用first作为参数调用number时,它会加载所有用户的数据库然后离开用户数组中只有number个元素。

first的{​​{3}}看起来像这样

def first(*args)
  if args.any?
    if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
      limit(*args).to_a
    else
      apply_finder_options(args.first).first
    end
  else
    find_first
  end
end

所以很好。但在recent Rails code中它是:

def first(*args)
  if args.any?
    if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
      to_a.first(*args)
    else
      apply_finder_options(args.first).first
    end
  else
    find_first
  end
end

因此,您可以看到first参数是Integer ActiveRecord是否加载了所有数据,将其转换为数组并调用Array的first方法,该方法具有以下行为:older version like Rails 3.0.7