【问题标题】:SQL slowness when doing ActiveRecord find on a HABTM relationship在 HABTM 关系上执行 ActiveRecord 查找时 SQL 缓慢
【发布时间】:2011-01-20 22:46:22
【问题描述】:

我正在运行带有 MySQL 数据库的 Rails 2.3.5。我在BooksUsers 之间有一个HABTM 关系,我正在尝试获取所有拥有指定书籍列表(由书籍名称数组定义)的用户。

我能够执行find 调用来检索此用户列表:

User.find(
  :all,
  :joins      => :books,
  :conditions => { :books => { :name => book_names } }
)

但是,事实证明这非常慢。在玩了 SQL 之后,我发现下面的调用运行得更快并且检索到相同的结果:

User.find_by_sql([
  "SELECT users.* FROM users
   INNER JOIN books_users ON users.id = books_users.user_id
   WHERE books_users.book_id IN (SELECT id FROM books WHERE books.name IN (?))",
  book_names
])

对于相同的查询,find 在我的计算机上调用大约需要 3000 毫秒,而find_by_sql 调用大约需要 200 毫秒;这是速度差异的一个完整幅度。我怀疑罪魁祸首与原来的find 调用被翻译成双重INNER JOIN SQL 查询有关,相当于以下内容:

[
  "SELECT users.* FROM users
   INNER JOIN books_users ON users.id = books_users.user_id
   INNER JOIN books ON books_users.book_id = books.id
   WHERE books.name IN (?)",
  book_names
]

我的问题是:

  • 有人知道为什么会这样吗?为什么使用嵌套的 SELECT 查询时双 INNER JOIN 比我的单 INNER JOIN 慢?
  • find_by_sql 调用并没有真正利用 Rails 为 HABTM 关系提供的内置支持。特别是,它显示了 Rails 支持通常从开发人员那里抽象出来的 books_users 连接表。有没有办法使用隐藏此的 find 调用来指定相同的查询?

【问题讨论】:

  • 您是否为books_users 表的book_iduser_id 字段创建了索引?
  • Ack... 我知道我忘记了什么。就是这样!添加索引后,查找查询现在需要 15 毫秒。
  • @dmarkow:将其添加为答案,以便我们给您积分

标签: mysql ruby-on-rails


【解决方案1】:

在上面的 cmets 之后,听起来您需要在 books_users 中的 book_iduser_id 字段上建立索引。

class AddIndices < ActiveRecord::Migration
  def self.up
    add_index :books_users, :book_id
    add_index :books_users, :user_id
  end

  def self.down
    remove_index :books_users, :book_id
    remove_index :books_users, :user_id
  end
end

【讨论】:

    【解决方案2】:

    使用 :include 与 :join 相比,连接效果更好吗?

    User.find(
      :all,
      :include    => :books,
      :conditions => { :books => { :name => book_names } }
    )
    

    【讨论】:

    • 很遗憾没有;它似乎同样慢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多