Оптимизация - Rails belongs_to имеет проблему n+1, как сделать чтоб в sql был join?
Имею записи логов, у них есть отсылка на пользователя.
Модель логов
class Syslog < ApplicationRecord
belongs_to :user
end
Модель пользователя ничего особенного не имеет, has_many я не добавлял там.
Теперь когда я делаю Syslog.all
А в представлении обращаюсь к пользователю:
<% @syslogs.each do |syslog| %>
<tr>
<td><%= syslog.datetime %></td>
<td><%= syslog.user.username %></td>
</tr>
<% end %>
В логах я вижу, что делается множество повторяющихся запросов.
Syslog Load (1.2ms) SELECT `SYSLOG`.* FROM `SYSLOG` INNER JOIN `USERS` ON `USERS`.`I_ID` = `SYSLOG`.`I_UID` WHERE (I_ELCAT <= '3') LIMIT 50
↳ app/views/syslogs/index.html.erb:13
User Load (1.4ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (1.1ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 2 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (1.3ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -20 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (2.2ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (1.2ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -11 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -11 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (1.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -17 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -11 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.1ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -1 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (2.1ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -15 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -20 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (1.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -12 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (1.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -13 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -13 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -13 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -13 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -13 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
CACHE User Load (0.0ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -13 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
User Load (0.8ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = -18 LIMIT 1
↳ app/views/syslogs/index.html.erb:16
Rendered syslogs/index.html.erb within layouts/application (Duration: 163.4ms | Allocations: 64237)
User Load (1.3ms) SELECT `USERS`.* FROM `USERS` WHERE `USERS`.`I_ID` = 11 LIMIT 1
Получается технически сначала выбираются все логи. А потом в цикле для каждого лога выбирается пользователь.
Мне надо сделать это одним или минимальным количеством запросов. Как этого добиться?
Ответы (1 шт):
Автор решения: Василиса
→ Ссылка
Это не надо делать через join, в ActiveRecord есть разные варианты прелоада для этого
@syslogs = Syslog.includes(:user).all