Пользовательский запрос ActiveRecord против загрузки find_by_sql

У меня есть собственный запрос, который выглядит так

self.account.websites.find(:all,:joins => [:group_websites => {:group => :users}],:conditions=>["users.id =?",self])

где self - это объект пользователя

Мне удалось сгенерировать эквивалентный SQL для того же

Вот как это выглядит

sql = "select * from websites INNER JOIN group_websites on group_websites.website_id = websites.id INNER JOIN groups on groups.id = group_websites.group_id INNER JOIN group_users ON (groups.id = group_users.group_id) INNER JOIN users on (users.id = group_users.user_id) where (websites.account_id = #{account_id} AND (users.id = #{user_id}))"

С приличным пониманием SQL и ActiveRecord я предположил, что (с чем большинство согласится) результат, полученный из вышеуказанного запроса, может занять больше времени по сравнению с результатом, полученным из find_by_sql (sql) one .

Но на удивление

Когда я запустил два вышеупомянутых, я обнаружил, что пользовательский запрос ActiveRecord опережает ActiveRecord "find_by_sql" с точки зрения времени загрузки. Вот результат теста.

Время загрузки пользовательского запроса ActiveRecord

Загрузка веб-сайта (0,9 мс)

Столбцы веб-сайта (1,0 мс)

время загрузки find_by_sql

Загрузка веб-сайта (1,3 мс)

Столбцы веб-сайта (1,0 мс)

Я повторил тест снова и снова, и результат все еще оставался таким же (с Custom Query, выигравшим битву)

Я знаю, что разница не такая большая, но все же я просто не могу понять, почему обычный запрос find_by_sql медленнее, чем пользовательский запрос

Кто-нибудь может пролить свет на это.

Спасибо, в любом случае

С уважением, Вирен Неги


person Viren    schedule 22.02.2011    source источник
comment
Запрос, сгенерированный обоими методами, одинаков? Если нет, не могли бы вы скопировать и вставить оба?   -  person Fernando Diaz Garrido    schedule 22.02.2011


Ответы (2)


В случае поиска запрос параметризуется; это означает, что база данных может кэшировать план запроса, и ему не нужно будет повторно анализировать и компилировать запрос.

В случае find_by_sql весь запрос передается в базу данных в виде строки. Это означает, что база данных не может кэшировать структуру запроса, и ее необходимо анализировать и компилировать каждый раз.

Я думаю, вы можете это проверить: попробуйте find_by_sql таким образом (параметризованный):

User.find_by_sql(["select * from websites INNER JOIN group_websites on group_websites.website_id = websites.id INNER JOIN groups on groups.id = group_websites.group_id INNER JOIN group_users ON (groups.id = group_users.group_id) INNER JOIN users on (users.id = group_users.user_id) where (websites.account_id = ? AND (users.id = ?))", account_id, users.id])
person DanSingerman    schedule 22.02.2011

Что ж, причина, вероятно, довольно проста - с настраиваемым SQL запрос SQL немедленно отправляется на сервер db для выполнения. Помните, что Ruby - это интерпретируемый язык, поэтому Rails генерирует новый SQL-запрос на основе метаязыка ORM, который вы использовали, прежде чем он может быть отправлен на фактический сервер db для выполнения. Я бы сказал, что дополнительные 0,1 мс - это время, необходимое фреймворку для генерации запроса.

person Jas    schedule 22.02.2011
comment
Я думаю, что кеширование db, а не кеширование фреймворка, имеет значение (согласно моему ответу). Кэширует ли RoR структуру запроса? Есть ссылка на код, где это делается? - person DanSingerman; 22.02.2011