Я запускаю Rails 2.3.5 с базой данных MySQL. У меня есть отношение HABTM между Books
и Users
, и я пытаюсь получить всех пользователей, у которых есть указанный список книг (определенный массивом имен книг).
Я могу выполнить вызов 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
транслируется в двойной SQL-запрос INNER JOIN
, эквивалентный следующему:
[
"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
]
Мои вопросы:
INNER JOIN
медленнее, чем мой единственный INNER JOIN
с вложенным SELECT
запросом?find_by_sql
не использует преимущества встроенной поддержки, которую Rails предоставляет для отношений HABTM. В частности, он всплывает в таблице соединений books_users
, что поддержка Rails обычно абстрагируется от разработчика. Есть ли способ указать один и тот же запрос с помощью вызова find
, который скрывает это?После комментариев выше, кажется, что вам нужны индексы в полях book_id
и user_id
в books_users
.
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
Используется ли: include vs.: join делает соединение лучше?
User.find(
:all,
:include => :books,
:conditions => { :books => { :name => book_names } }
)
book_id
иuser_id
для своей таблицыbooks_users
?