【问题标题】:ActiveRecord includes over join Table very slow in Rails 4.1.2ActiveRecord 在 Rails 4.1.2 中包含过度连接表非常慢
【发布时间】:2014-08-19 11:34:01
【问题描述】:

我刚刚从 Rails 4.0.2 更新到 Rails 4.1.2 并意识到 ActiveRecord 包含变得非常缓慢。过去只需几毫秒的查看时间现在几乎需要 5 分钟。

我通过模型中的 has_and_belongs_to_many 连接表通过连接表连接两个表 Item 和 Keyword。我有近 3000 个项目、3000 个关键字和 8000 个连接表条目。

获取所有项目并包含所有关键字过去非常快,但现在需要很长时间:

Item.includes(:keywords)

我比较了 4.0.2 和 4.1.2 的 SQL,Rails 似乎不再在 Rails 4.1.2 中使用内部连接查询。数据库响应时间非常快,所以这不是问题。

SQL for Rails 4.0.2

项目加载 (5.8ms) SELECT items.* FROM items

SQL (4.6ms) SELECT keywords.*, t0.item_id AS ar_association_key_name FROM keywords INNER JOIN items_keywords t0keywords.id = t0.keyword_id 其中t0.item_id IN (, ...)

SQL for Rails 4.1.2

项目加载 (3.7ms) SELECT items.* FROM items

HABTM_Keywords 加载 (2.8ms) SELECT items_keywords.* FROM items_keywords WHERE items_keywords.item_id IN (, ...)

关键字加载 (0.6ms) SELECT keywords.* FROM keywords WHERE keywords.id IN (, ...)

这是一个已知问题吗?我在这方面找不到任何东西,所以我认为最好在报告错误报告之前先询问社区。​​p>

现在我将 Rails 版本改回 4.0.2。

谢谢比约恩

【问题讨论】:

  • 如果你可以让一个准系统简单的案例表现出这种行为,那么我建议用这个例子提交一份报告。
  • 每个版本的 Rails 生成的 SQL 是什么?使用Item.includes(:keywords).to_sql 找出答案。
  • 我编辑了问题并包含了生成的 SQL。它在 4.1.2 中发生了变化,不再使用内部连接,现在执行三个单独的查询。

标签: ruby-on-rails activerecord


【解决方案1】:

这是 4.1.2 中的一个错误,在这里解决:

https://github.com/rails/rails/pull/15675

【讨论】:

    【解决方案2】:

    您可以通过显式引用关联来避免此处的性能回归:

    Item.includes(:keywords).references(:keywords)
    

    但问题是 Rails 范围内的,虽然有修复,但还没有在任何版本中,所以我现在把它放在初始化程序中。

    对我来说,这仍然很慢,但只有没有修复时的一半左右。

    module ActiveRecord
      # FIXME: this is a fix pulled from https://github.com/rails/rails/pull/15675
      # for a serious performance issue, look to remove it on the next Rails upgrade
      module Associations::Builder
        class HasAndBelongsToMany
          def hash
            object_id.hash
          end
    
          def ==(other)
            equal?(other)
          end
          alias :eql? :==
        end
      end
      module AttributeMethods
        module PrimaryKey
          def id
            return unless self.class.primary_key
            sync_with_transaction_state
            read_attribute(self.class.primary_key)
          end
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-24
      • 2011-06-01
      • 2015-01-05
      相关资源
      最近更新 更多