【问题标题】:MySql in Rails 3 fast with User.first and slow with User.first(1) - why?Rails 3 中的 MySql 使用 User.first 速度快,而使用 User.first(1) 速度慢 - 为什么?
【发布时间】:2013-01-23 05:59:01
【问题描述】:

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

User.first

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

User.first(1)

这需要几秒钟。这可能是什么原因造成的?

注意:同样的事情发生在

User.last

User.last(1)

【问题讨论】:

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


    【解决方案1】:

    我在 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 作为参数时,它会加载 DB 的所有用户,然后只留下 number 元素用户数组。

    firstrecent Rails code 中看起来像这样

    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
    

    所以还可以。但在older version like Rails 3.0.7 是:

    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 方法,该方法具有以下行为:http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-first

    【讨论】:

    • 令人着迷!所以这似乎是 3.0.7 中的一个错误?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 2020-01-20
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    相关资源
    最近更新 更多