Связи Rails Active Record с Enumerable

В некоторых случаях, когда я получаю отношение ActiveRecord, я испытываю странное поведение с .each в ActiveRecord::Relation

Кажется, когда ActiveRecord::Relation делегирует :each в :to => :to_a (источник)

@tasks = Task.find_task(list, {:week_id => 1})

По сути, есть длинный метод класса, который принимает объект (list и хэш с :week_id)

В этом методе find_task происходит множество фильтров и запросов, но в итоге он возвращает отношение к @tasks.

Затем в шаблоне у меня есть:

<% @tasks.each do |task| %>
.
.
.
<% end %>

По какой-то причине, независимо от размера @tasks, это занимает ~3 минуты. Я могу воспроизвести это же поведение, вызвав @tasks.to_a. Даже если @tasks экземпляр ActiveRecord::Relation состоит только из двух записей, вызов to_a для них занимает> 3 минуты.

Это происходит не на всех :week_id, а только на определенном week_id, например: :week_id => 1

SQL выполняется нормально, и я возвращаю отношение, просто кажется, что это проблема с перечислением в конкретном ActiveRecord::Relation.

Обновить

Внутри алгоритма (я думаю, это означает метод класса) я делаю МНОГО нетерпеливой загрузки. Итак, Postgres выполняет много операций LEFT OUTER JOIN, и я проиндексировал все таблицы, в которых это должно происходить.

Объясняющий анализ показывает, что все сканирования index scans и, как выясняется, запрос выполняется просто отлично с большим количеством нетерпеливой загрузки... и я получаю нетерпеливо загруженный 'ActiveRecord::Relation` за разумное время.

Обновление 2 Пока этот процесс занимает 3 минуты, я вижу процесс postgres, работающий в течение нескольких секунд, а затем я вижу это в течение 3 минут в качестве вывода в top:

 PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+    COMMAND                                                            
 8685 dylan     20   0 3407m 2.6g  904 R 99.7 69.1   1:14.49 /usr/local/bin/ruby script/rails s

Когда он наконец завершится, сервер покажет это;

  • нетерпеливая загрузка: 200 ms, 139 ms затем
  • большой SQL-запрос с большим количеством LEFT OUTER JOINS in 33,000 ms (длинный, но не там, где большинство), затем
  • 257,000 ms в шаблоне.

И когда я повторяю поведение в шаблоне, я вижу, что вызов to_a для отношения @tasks занимает ~3-4 минуты.

Итак, когда мой сервер сообщает мне, что все время потрачено на шаблон, и я вижу, что вызов перечислимого для отношения занимает вечность, это когда запрос выполняется? Хотя в top я вижу только запущенный процесс ruby?


person dylanjha    schedule 18.10.2012    source источник


Ответы (2)


Я знаю, что это старый пост, но для дальнейшего использования это можно решить, используя вместо этого find_each.

Дополнительную информацию можно найти в руководствах по Ruby on Rails. .

person Jorge Rodríguez    schedule 26.01.2015

Проблема была с жадной загрузкой. При вызове перечисляемого метода для экземпляра ActiveRecord::Relation он делегируется .to_a, что может занять очень много времени с огромным набором отношений. Несмотря на то, что я зацикливался на @tasks, я нетерпеливо загружал так много объектов, что .to_a занимало слишком много времени.

Мое краткосрочное решение состоит в том, чтобы просто загружать меньше объектов, хотя в конечном итоге это причиняет мне боль с n + 1 запросами.

person dylanjha    schedule 19.10.2012